From 8e38b928490516d308bdceebc4ad032852bf2716 Mon Sep 17 00:00:00 2001 From: Chungying Lu Date: Wed, 15 Mar 2023 15:31:56 +0800 Subject: [PATCH] feat(mt8188): add apu power on/off control Add mt8188 apu power on/off control Change-Id: I8e28bf7a4ad4067553981c67c4c2225fdd802859 Signed-off-by: Chungying Lu Signed-off-by: jason-ch chen --- plat/mediatek/drivers/apusys/apusys.c | 29 ++++ plat/mediatek/drivers/apusys/apusys.h | 6 + .../drivers/apusys/mt8188/apusys_power.c | 133 ++++++++++++++++++ .../drivers/apusys/mt8188/apusys_power.h | 45 ++++++ plat/mediatek/mt8188/include/platform_def.h | 3 + 5 files changed, 216 insertions(+) diff --git a/plat/mediatek/drivers/apusys/apusys.c b/plat/mediatek/drivers/apusys/apusys.c index 1d34627fa..c82b3a7a8 100644 --- a/plat/mediatek/drivers/apusys/apusys.c +++ b/plat/mediatek/drivers/apusys/apusys.c @@ -11,6 +11,35 @@ #include "apusys.h" #include "apusys_power.h" #include +#include + +static u_register_t apusys_kernel_handler(u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *handle, + struct smccc_res *smccc_ret) +{ + uint32_t request_ops; + int32_t ret = -1; + + request_ops = (uint32_t)x1; + + switch (request_ops) { + case MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_ON: + ret = apusys_kernel_apusys_pwr_top_on(); + break; + case MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_OFF: + ret = apusys_kernel_apusys_pwr_top_off(); + break; + default: + ERROR(MODULE_TAG "%s unknown request_ops = %x\n", MODULE_TAG, request_ops); + break; + } + + return ret; +} +DECLARE_SMC_HANDLER(MTK_SIP_APUSYS_CONTROL, apusys_kernel_handler); int apusys_init(void) { diff --git a/plat/mediatek/drivers/apusys/apusys.h b/plat/mediatek/drivers/apusys/apusys.h index 5fdd2ec95..1592cff83 100644 --- a/plat/mediatek/drivers/apusys/apusys.h +++ b/plat/mediatek/drivers/apusys/apusys.h @@ -9,4 +9,10 @@ #define MODULE_TAG "[APUSYS]" +enum MTK_APUSYS_KERNEL_OP { + MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_ON, /* 0 */ + MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_OFF,/* 1 */ + MTK_APUSYS_KERNEL_OP_NUM, +}; + #endif diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_power.c b/plat/mediatek/drivers/apusys/mt8188/apusys_power.c index d7b0d2455..ac62f2fa1 100644 --- a/plat/mediatek/drivers/apusys/mt8188/apusys_power.c +++ b/plat/mediatek/drivers/apusys/mt8188/apusys_power.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,9 @@ #include "apusys_power.h" #include +static spinlock_t apu_lock; +static bool apusys_top_on; + static int apu_poll(uintptr_t reg, uint32_t mask, uint32_t value, uint32_t timeout_us) { uint32_t reg_val, count; @@ -43,6 +47,135 @@ static int apu_poll(uintptr_t reg, uint32_t mask, uint32_t value, uint32_t timeo return -1; } +static void apu_xpu2apusys_d4_slv_en(enum APU_D4_SLV_CTRL en) +{ + switch (en) { + case D4_SLV_OFF: + mmio_setbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI21_CTRL_0, + INFRA_FMEM_BUS_u_SI21_CTRL_EN); + mmio_setbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI22_CTRL_0, + INFRA_FMEM_BUS_u_SI22_CTRL_EN); + mmio_setbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI11_CTRL_0, + INFRA_FMEM_BUS_u_SI11_CTRL_EN); + mmio_setbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_0, + INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_EN); + break; + case D4_SLV_ON: + mmio_clrbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI21_CTRL_0, + INFRA_FMEM_BUS_u_SI21_CTRL_EN); + mmio_clrbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI22_CTRL_0, + INFRA_FMEM_BUS_u_SI22_CTRL_EN); + mmio_clrbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_BUS_u_SI11_CTRL_0, + INFRA_FMEM_BUS_u_SI11_CTRL_EN); + mmio_clrbits_32(BCRM_FMEM_PDN_BASE + INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_0, + INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_EN); + break; + default: + ERROR(MODULE_TAG "%s invalid op: %d\n", __func__, en); + break; + } +} + +static void apu_pwr_flow_remote_sync(uint32_t cfg) +{ + mmio_write_32(APU_MBOX0_BASE + PWR_FLOW_SYNC_REG, (cfg & 0x1)); +} + +int apusys_kernel_apusys_pwr_top_on(void) +{ + int ret; + + spin_lock(&apu_lock); + + if (apusys_top_on == true) { + INFO(MODULE_TAG "%s: APUSYS already powered on!\n", __func__); + spin_unlock(&apu_lock); + return 0; + } + + apu_pwr_flow_remote_sync(1); + + mmio_setbits_32(APU_RPC_BASE + APU_RPC_TOP_SEL_1, AFC_ENA); + + mmio_write_32(APU_RPC_BASE + APU_RPC_TOP_CON, REG_WAKEUP_SET); + + ret = apu_poll(APU_RPC_BASE + APU_RPC_INTF_PWR_RDY, + PWR_RDY, PWR_RDY, APU_TOP_ON_POLLING_TIMEOUT_US); + if (ret != 0) { + ERROR(MODULE_TAG "%s polling RPC RDY timeout, ret %d\n", __func__, ret); + spin_unlock(&apu_lock); + return ret; + } + + ret = apu_poll(APU_RPC_BASE + APU_RPC_STATUS, + RPC_STATUS_RDY, RPC_STATUS_RDY, APU_TOP_ON_POLLING_TIMEOUT_US); + if (ret != 0) { + ERROR(MODULE_TAG "%s polling ARE FSM timeout, ret %d\n", __func__, ret); + spin_unlock(&apu_lock); + return ret; + } + + mmio_write_32(APU_VCORE_BASE + APUSYS_VCORE_CG_CLR, CG_CLR); + mmio_write_32(APU_RCX_BASE + APU_RCX_CG_CLR, CG_CLR); + + apu_xpu2apusys_d4_slv_en(D4_SLV_OFF); + + apusys_top_on = true; + + spin_unlock(&apu_lock); + return ret; +} + +static void apu_sleep_rpc_rcx(void) +{ + mmio_write_32(APU_RPC_BASE + APU_RPC_TOP_CON, REG_WAKEUP_CLR); + udelay(10); + + mmio_setbits_32(APU_RPC_BASE + APU_RPC_TOP_SEL, (RPC_CTRL | RSV10)); + udelay(10); + + mmio_setbits_32(APU_RPC_BASE + APU_RPC_TOP_CON, CLR_IRQ); + udelay(10); + + mmio_setbits_32(APU_RPC_BASE + APU_RPC_TOP_CON, SLEEP_REQ); + udelay(100); +} + +int apusys_kernel_apusys_pwr_top_off(void) +{ + int ret; + + spin_lock(&apu_lock); + + if (apusys_top_on == false) { + INFO(MODULE_TAG "%s: APUSYS already powered off!\n", __func__); + spin_unlock(&apu_lock); + return 0; + } + + apu_xpu2apusys_d4_slv_en(D4_SLV_ON); + + if (mmio_read_32(APU_MBOX0_BASE + PWR_FLOW_SYNC_REG) == 0) { + apu_pwr_flow_remote_sync(1); + } else { + apu_sleep_rpc_rcx(); + } + + ret = apu_poll(APU_RPC_BASE + APU_RPC_INTF_PWR_RDY, + PWR_RDY, PWR_OFF, APU_TOP_OFF_POLLING_TIMEOUT_US); + if (ret != 0) { + ERROR(MODULE_TAG "%s timeout to wait RPC sleep (val:%d), ret %d\n", + __func__, APU_TOP_OFF_POLLING_TIMEOUT_US, ret); + spin_unlock(&apu_lock); + return ret; + } + + apusys_top_on = false; + + spin_unlock(&apu_lock); + return ret; +} + static void get_pll_pcw(const uint32_t clk_rate, uint32_t *r1, uint32_t *r2) { unsigned int fvco = clk_rate; diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_power.h b/plat/mediatek/drivers/apusys/mt8188/apusys_power.h index 1f68bd23e..b4968d6d7 100644 --- a/plat/mediatek/drivers/apusys/mt8188/apusys_power.h +++ b/plat/mediatek/drivers/apusys/mt8188/apusys_power.h @@ -24,6 +24,11 @@ enum APU_ARE_ID { APU_ARE_NUM, }; +enum APU_D4_SLV_CTRL { + D4_SLV_OFF = 0, + D4_SLV_ON, +}; + #define APU_POLL_STEP_US (5) #define OUT_CLK_FREQ_MIN (1500) @@ -40,20 +45,26 @@ enum APU_ARE_ID { #define APU_ARE_POLLING_TIMEOUT_US (10000) /* APU related reg */ +#define APU_VCORE_BASE (APU_RCX_VCORE_CONFIG) +#define APU_RCX_BASE (APU_RCX_CONFIG) #define APU_RPC_BASE (APU_RPCTOP) #define APU_PCU_BASE (APU_PCUTOP) #define APU_ARE0_BASE (APU_ARETOP_ARE0) #define APU_ARE1_BASE (APU_ARETOP_ARE1) #define APU_ARE2_BASE (APU_ARETOP_ARE2) +#define APU_MBOX0_BASE (APU_MBOX0) #define APU_AO_CTL_BASE (APU_AO_CTRL) #define APU_PLL_BASE (APU_PLL) #define APU_ACC_BASE (APU_ACC) #define APU_ACX0_RPC_LITE_BASE (APU_ACX0_RPC_LITE) /* RPC offset define */ +#define APU_RPC_TOP_CON (0x0000) #define APU_RPC_TOP_SEL (0x0004) +#define APU_RPC_STATUS (0x0014) #define APU_RPC_TOP_SEL_1 (0x0018) #define APU_RPC_HW_CON (0x001c) +#define APU_RPC_INTF_PWR_RDY (0x0044) #define APU_RPC_SW_TYPE0 (0x0200) /* RPC control */ @@ -68,6 +79,15 @@ enum APU_ARE_ID { #define RPC_CTRL (0x0000009e) #define RPC_TOP_CTRL (0x0800501e) #define RPC_TOP_CTRL1 BIT(20) +#define AFC_ENA BIT(16) +#define REG_WAKEUP_SET BIT(8) +#define REG_WAKEUP_CLR BIT(12) +#define PWR_RDY BIT(0) +#define PWR_OFF (0) +#define RPC_STATUS_RDY BIT(29) +#define RSV10 BIT(10) +#define CLR_IRQ (0x6) +#define SLEEP_REQ BIT(0) /* PLL offset define */ #define PLL4H_PLL1_CON1 (0x000c) @@ -137,6 +157,12 @@ enum APU_ARE_ID { #define ARE_ENTRY1_SRAM_L_INIT (0x76543210) #define ARE_CONFG_INI BIT(2) +/* VCORE offset define */ +#define APUSYS_VCORE_CG_CLR (0x0008) + +/* RCX offset define */ +#define APU_RCX_CG_CLR (0x0008) + /* SPM offset define */ #define APUSYS_BUCK_ISOLATION (0x03ec) @@ -149,6 +175,18 @@ enum APU_ARE_ID { /* apu_rcx_ao_ctrl control */ #define VCORE_ARE_REQ BIT(2) +/* xpu2apusys */ +#define INFRA_FMEM_BUS_u_SI21_CTRL_0 (0x002c) +#define INFRA_FMEM_BUS_u_SI22_CTRL_0 (0x0044) +#define INFRA_FMEM_BUS_u_SI11_CTRL_0 (0x0048) +#define INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_0 (0x01d0) + +/* xpu2apusys */ +#define INFRA_FMEM_BUS_u_SI21_CTRL_EN BIT(12) +#define INFRA_FMEM_BUS_u_SI22_CTRL_EN BIT(13) +#define INFRA_FMEM_BUS_u_SI11_CTRL_EN BIT(11) +#define INFRA_FMEM_M6M7_BUS_u_SI24_CTRL_EN BIT(15) + /* PCU offset define */ #define APU_PCU_CTRL_SET (0x0000) #define APU_PCU_BUCK_STEP_SEL (0x0030) @@ -188,6 +226,13 @@ enum APU_ARE_ID { #define APU_RPC_SW_TYPE8 (0x0220) #define APU_RPC_SW_TYPE9 (0x0224) +/* power flow sync */ +#define PWR_FLOW_SYNC_REG (0x0440) + +#define CG_CLR (0xffffffff) + int apusys_power_init(void); +int apusys_kernel_apusys_pwr_top_on(void); +int apusys_kernel_apusys_pwr_top_off(void); #endif /* APUSYS_POWER_H */ diff --git a/plat/mediatek/mt8188/include/platform_def.h b/plat/mediatek/mt8188/include/platform_def.h index 576dc3df9..fc9725e5b 100644 --- a/plat/mediatek/mt8188/include/platform_def.h +++ b/plat/mediatek/mt8188/include/platform_def.h @@ -28,6 +28,9 @@ * APUSYS related constants ******************************************************************************/ #define BCRM_FMEM_PDN_BASE (IO_PHYS + 0x00276000) +#define APU_RCX_CONFIG (IO_PHYS + 0x09020000) +#define APU_RCX_VCORE_CONFIG (IO_PHYS + 0x090e0000) +#define APU_MBOX0 (IO_PHYS + 0x090e1000) #define APU_RPCTOP (IO_PHYS + 0x090f0000) #define APU_PCUTOP (IO_PHYS + 0x090f1000) #define APU_AO_CTRL (IO_PHYS + 0x090f2000) -- 2.39.5