1*5f748b3cSKun Lu /* 2*5f748b3cSKun Lu * Copyright (c) 2025, Mediatek Inc. All rights reserved. 3*5f748b3cSKun Lu * 4*5f748b3cSKun Lu * SPDX-License-Identifier: BSD-3-Clause 5*5f748b3cSKun Lu */ 6*5f748b3cSKun Lu 7*5f748b3cSKun Lu #include <assert.h> 8*5f748b3cSKun Lu #include <stddef.h> 9*5f748b3cSKun Lu #include <stdio.h> 10*5f748b3cSKun Lu #include <string.h> 11*5f748b3cSKun Lu 12*5f748b3cSKun Lu #include <arch.h> 13*5f748b3cSKun Lu #include <common/debug.h> 14*5f748b3cSKun Lu #include <drivers/console.h> 15*5f748b3cSKun Lu #include <lib/bakery_lock.h> 16*5f748b3cSKun Lu #include <lib/mmio.h> 17*5f748b3cSKun Lu #include <lib/utils_def.h> 18*5f748b3cSKun Lu 19*5f748b3cSKun Lu #include <constraints/mt_spm_rc_api.h> 20*5f748b3cSKun Lu #include <constraints/mt_spm_rc_internal.h> 21*5f748b3cSKun Lu #include <drivers/spm/mt_spm_resource_req.h> 22*5f748b3cSKun Lu #include <lib/mtk_init/mtk_init.h> 23*5f748b3cSKun Lu #include <lib/pm/mtk_pm.h> 24*5f748b3cSKun Lu #include <lpm_v2/mt_lp_rm.h> 25*5f748b3cSKun Lu #include <lpm_v2/mt_lp_rqm.h> 26*5f748b3cSKun Lu #include <lpm_v2/mt_lpm_smc.h> 27*5f748b3cSKun Lu #include <mt_cirq.h> 28*5f748b3cSKun Lu #include <mt_gic_v3.h> 29*5f748b3cSKun Lu #include <mt_plat_spm_setting.h> 30*5f748b3cSKun Lu #include <mt_spm.h> 31*5f748b3cSKun Lu #include <mt_spm_common.h> 32*5f748b3cSKun Lu #include <mt_spm_conservation.h> 33*5f748b3cSKun Lu #include <mt_spm_constraint.h> 34*5f748b3cSKun Lu #include <mt_spm_dispatcher.h> 35*5f748b3cSKun Lu #include <mt_spm_hwreq.h> 36*5f748b3cSKun Lu #include <mt_spm_idle.h> 37*5f748b3cSKun Lu #include <mt_spm_internal.h> 38*5f748b3cSKun Lu #include <mt_spm_reg.h> 39*5f748b3cSKun Lu #include <mt_spm_suspend.h> 40*5f748b3cSKun Lu #include <mtk_mmap_pool.h> 41*5f748b3cSKun Lu #include <platform_def.h> 42*5f748b3cSKun Lu #include <sleep_def.h> 43*5f748b3cSKun Lu 44*5f748b3cSKun Lu #ifdef MT_SPM_USING_BAKERY_LOCK 45*5f748b3cSKun Lu DEFINE_BAKERY_LOCK(spm_lock); 46*5f748b3cSKun Lu #define plat_spm_lock_init() bakery_lock_init(&spm_lock) 47*5f748b3cSKun Lu #else 48*5f748b3cSKun Lu spinlock_t spm_lock; 49*5f748b3cSKun Lu #define plat_spm_lock_init() 50*5f748b3cSKun Lu #endif 51*5f748b3cSKun Lu 52*5f748b3cSKun Lu static uint32_t spm_irq_num; 53*5f748b3cSKun Lu 54*5f748b3cSKun Lu void spm_set_sysclk_settle(void) 55*5f748b3cSKun Lu { 56*5f748b3cSKun Lu uint32_t settle; 57*5f748b3cSKun Lu 58*5f748b3cSKun Lu mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE); 59*5f748b3cSKun Lu settle = mmio_read_32(SPM_CLK_SETTLE); 60*5f748b3cSKun Lu 61*5f748b3cSKun Lu INFO("md_settle = %u, settle = %u\n", SPM_SYSCLK_SETTLE, settle); 62*5f748b3cSKun Lu } 63*5f748b3cSKun Lu 64*5f748b3cSKun Lu void spm_set_irq_num(uint32_t num) 65*5f748b3cSKun Lu { 66*5f748b3cSKun Lu spm_irq_num = num; 67*5f748b3cSKun Lu } 68*5f748b3cSKun Lu 69*5f748b3cSKun Lu void spm_irq0_handler(uint64_t x1, uint64_t x2) 70*5f748b3cSKun Lu { 71*5f748b3cSKun Lu if (x2 == 0) { 72*5f748b3cSKun Lu mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM); 73*5f748b3cSKun Lu mmio_write_32(SPM_IRQ_STA, x1); 74*5f748b3cSKun Lu mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT0); 75*5f748b3cSKun Lu } 76*5f748b3cSKun Lu } 77*5f748b3cSKun Lu 78*5f748b3cSKun Lu static int spm_ap_mdsrc_ack(void) 79*5f748b3cSKun Lu { 80*5f748b3cSKun Lu int ack, md_state = 0; 81*5f748b3cSKun Lu 82*5f748b3cSKun Lu /* Check ap_mdsrc_ack = 1'b1, for md internal resource on ack */ 83*5f748b3cSKun Lu ack = !!(mmio_read_32(AP_MDSRC_REQ) & AP_MDSMSRC_ACK_LSB); 84*5f748b3cSKun Lu 85*5f748b3cSKun Lu if (!ack) { 86*5f748b3cSKun Lu /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */ 87*5f748b3cSKun Lu md_state = !!(mmio_read_32(SPM_REQ_STA_9) & MD_APSRC_REQ_LSB); 88*5f748b3cSKun Lu 89*5f748b3cSKun Lu ERROR("[SPM] error: md_sleep = %d\n", md_state); 90*5f748b3cSKun Lu ERROR("%s can not get AP_MDSRC_ACK\n", __func__); 91*5f748b3cSKun Lu return -1; 92*5f748b3cSKun Lu } 93*5f748b3cSKun Lu return 0; 94*5f748b3cSKun Lu } 95*5f748b3cSKun Lu 96*5f748b3cSKun Lu static void spm_ap_mdsrc_req(int set) 97*5f748b3cSKun Lu { 98*5f748b3cSKun Lu spm_lock_get(); 99*5f748b3cSKun Lu 100*5f748b3cSKun Lu if (set) 101*5f748b3cSKun Lu mmio_setbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB); 102*5f748b3cSKun Lu else 103*5f748b3cSKun Lu mmio_clrbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB); 104*5f748b3cSKun Lu 105*5f748b3cSKun Lu spm_lock_release(); 106*5f748b3cSKun Lu } 107*5f748b3cSKun Lu 108*5f748b3cSKun Lu static int spm_is_md_sleep(void *priv) 109*5f748b3cSKun Lu { 110*5f748b3cSKun Lu int md_state = 0; 111*5f748b3cSKun Lu int *sleep = (int *)priv; 112*5f748b3cSKun Lu 113*5f748b3cSKun Lu if (!priv) 114*5f748b3cSKun Lu return -1; 115*5f748b3cSKun Lu 116*5f748b3cSKun Lu /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */ 117*5f748b3cSKun Lu md_state = !!(mmio_read_32(SPM_REQ_STA_9) & MD_APSRC_REQ_LSB); 118*5f748b3cSKun Lu 119*5f748b3cSKun Lu if (md_state == 0) 120*5f748b3cSKun Lu *sleep = 1; 121*5f748b3cSKun Lu else 122*5f748b3cSKun Lu *sleep = 0; 123*5f748b3cSKun Lu 124*5f748b3cSKun Lu return 0; 125*5f748b3cSKun Lu } 126*5f748b3cSKun Lu 127*5f748b3cSKun Lu static void spm_ap_gpueb_pll_control(int set) 128*5f748b3cSKun Lu { 129*5f748b3cSKun Lu spm_lock_get(); 130*5f748b3cSKun Lu 131*5f748b3cSKun Lu if (set) 132*5f748b3cSKun Lu mmio_setbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB); 133*5f748b3cSKun Lu else 134*5f748b3cSKun Lu mmio_clrbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB); 135*5f748b3cSKun Lu 136*5f748b3cSKun Lu spm_lock_release(); 137*5f748b3cSKun Lu } 138*5f748b3cSKun Lu 139*5f748b3cSKun Lu static uint32_t spm_ap_gpueb_get_pwr_status(void) 140*5f748b3cSKun Lu { 141*5f748b3cSKun Lu uint32_t ret; 142*5f748b3cSKun Lu 143*5f748b3cSKun Lu ret = mmio_read_32(XPU_PWR_STATUS); 144*5f748b3cSKun Lu 145*5f748b3cSKun Lu return ret; 146*5f748b3cSKun Lu } 147*5f748b3cSKun Lu 148*5f748b3cSKun Lu static uint32_t spm_ap_gpueb_get_mfg0_pwr_con(void) 149*5f748b3cSKun Lu { 150*5f748b3cSKun Lu uint32_t ret; 151*5f748b3cSKun Lu 152*5f748b3cSKun Lu ret = mmio_read_32(MFG0_PWR_CON); 153*5f748b3cSKun Lu 154*5f748b3cSKun Lu return ret; 155*5f748b3cSKun Lu } 156*5f748b3cSKun Lu 157*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT 158*5f748b3cSKun Lu struct mt_lp_res_req rq_xo_fpm = { 159*5f748b3cSKun Lu .res_id = MT_LP_RQ_XO_FPM, 160*5f748b3cSKun Lu .res_rq = MT_SPM_XO_FPM, 161*5f748b3cSKun Lu .res_usage = 0, 162*5f748b3cSKun Lu }; 163*5f748b3cSKun Lu 164*5f748b3cSKun Lu struct mt_lp_res_req rq_26m = { 165*5f748b3cSKun Lu .res_id = MT_LP_RQ_26M, 166*5f748b3cSKun Lu .res_rq = MT_SPM_26M, 167*5f748b3cSKun Lu .res_usage = 0, 168*5f748b3cSKun Lu }; 169*5f748b3cSKun Lu 170*5f748b3cSKun Lu struct mt_lp_res_req rq_infra = { 171*5f748b3cSKun Lu .res_id = MT_LP_RQ_INFRA, 172*5f748b3cSKun Lu .res_rq = MT_SPM_INFRA, 173*5f748b3cSKun Lu .res_usage = 0, 174*5f748b3cSKun Lu }; 175*5f748b3cSKun Lu 176*5f748b3cSKun Lu struct mt_lp_res_req rq_syspll = { 177*5f748b3cSKun Lu .res_id = MT_LP_RQ_SYSPLL, 178*5f748b3cSKun Lu .res_rq = MT_SPM_SYSPLL, 179*5f748b3cSKun Lu .res_usage = 0, 180*5f748b3cSKun Lu }; 181*5f748b3cSKun Lu 182*5f748b3cSKun Lu struct mt_lp_res_req rq_dram_s0 = { 183*5f748b3cSKun Lu .res_id = MT_LP_RQ_DRAM, 184*5f748b3cSKun Lu .res_rq = MT_SPM_DRAM_S0, 185*5f748b3cSKun Lu .res_usage = 0, 186*5f748b3cSKun Lu }; 187*5f748b3cSKun Lu 188*5f748b3cSKun Lu struct mt_lp_res_req rq_dram_s1 = { 189*5f748b3cSKun Lu .res_id = MT_LP_RQ_DRAM, 190*5f748b3cSKun Lu .res_rq = MT_SPM_DRAM_S1, 191*5f748b3cSKun Lu .res_usage = 0, 192*5f748b3cSKun Lu }; 193*5f748b3cSKun Lu 194*5f748b3cSKun Lu struct mt_lp_res_req rq_vcore = { 195*5f748b3cSKun Lu .res_id = MT_LP_RQ_VCORE, 196*5f748b3cSKun Lu .res_rq = MT_SPM_VCORE, 197*5f748b3cSKun Lu .res_usage = 0, 198*5f748b3cSKun Lu }; 199*5f748b3cSKun Lu 200*5f748b3cSKun Lu struct mt_lp_res_req rq_emi = { 201*5f748b3cSKun Lu .res_id = MT_LP_RQ_EMI, 202*5f748b3cSKun Lu .res_rq = MT_SPM_EMI, 203*5f748b3cSKun Lu .res_usage = 0, 204*5f748b3cSKun Lu }; 205*5f748b3cSKun Lu 206*5f748b3cSKun Lu struct mt_lp_res_req rq_pmic = { 207*5f748b3cSKun Lu .res_id = MT_LP_RQ_PMIC, 208*5f748b3cSKun Lu .res_rq = MT_SPM_PMIC, 209*5f748b3cSKun Lu .res_usage = 0, 210*5f748b3cSKun Lu }; 211*5f748b3cSKun Lu 212*5f748b3cSKun Lu struct mt_lp_res_req *spm_resources[] = { 213*5f748b3cSKun Lu &rq_xo_fpm, &rq_26m, &rq_infra, &rq_syspll, &rq_dram_s0, 214*5f748b3cSKun Lu &rq_dram_s1, &rq_vcore, &rq_emi, &rq_pmic, NULL, 215*5f748b3cSKun Lu }; 216*5f748b3cSKun Lu 217*5f748b3cSKun Lu struct mt_resource_req_manager plat_mt8189_rq = { 218*5f748b3cSKun Lu .res = spm_resources, 219*5f748b3cSKun Lu }; 220*5f748b3cSKun Lu 221*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_vcore = { 222*5f748b3cSKun Lu .is_valid = spm_is_valid_rc_vcore, 223*5f748b3cSKun Lu .update = spm_update_rc_vcore, 224*5f748b3cSKun Lu .allow = spm_allow_rc_vcore, 225*5f748b3cSKun Lu .run = spm_run_rc_vcore, 226*5f748b3cSKun Lu .reset = spm_reset_rc_vcore, 227*5f748b3cSKun Lu .get_status = spm_get_status_rc_vcore, 228*5f748b3cSKun Lu }; 229*5f748b3cSKun Lu 230*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_bus26m = { 231*5f748b3cSKun Lu .is_valid = spm_is_valid_rc_bus26m, 232*5f748b3cSKun Lu .update = spm_update_rc_bus26m, 233*5f748b3cSKun Lu .allow = spm_allow_rc_bus26m, 234*5f748b3cSKun Lu .run = spm_run_rc_bus26m, 235*5f748b3cSKun Lu .reset = spm_reset_rc_bus26m, 236*5f748b3cSKun Lu .get_status = spm_get_status_rc_bus26m, 237*5f748b3cSKun Lu }; 238*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_syspll = { 239*5f748b3cSKun Lu .is_valid = spm_is_valid_rc_syspll, 240*5f748b3cSKun Lu .update = spm_update_rc_syspll, 241*5f748b3cSKun Lu .allow = spm_allow_rc_syspll, 242*5f748b3cSKun Lu .run = spm_run_rc_syspll, 243*5f748b3cSKun Lu .reset = spm_reset_rc_syspll, 244*5f748b3cSKun Lu .get_status = spm_get_status_rc_syspll, 245*5f748b3cSKun Lu }; 246*5f748b3cSKun Lu 247*5f748b3cSKun Lu struct mt_resource_constraint *plat_constraints[] = { 248*5f748b3cSKun Lu &plat_constraint_vcore, 249*5f748b3cSKun Lu &plat_constraint_bus26m, 250*5f748b3cSKun Lu &plat_constraint_syspll, 251*5f748b3cSKun Lu NULL, 252*5f748b3cSKun Lu }; 253*5f748b3cSKun Lu #endif 254*5f748b3cSKun Lu 255*5f748b3cSKun Lu int mt_spm_hwctrl(uint32_t type, int set, void *priv) 256*5f748b3cSKun Lu { 257*5f748b3cSKun Lu int ret = 0; 258*5f748b3cSKun Lu 259*5f748b3cSKun Lu switch (type) { 260*5f748b3cSKun Lu case PLAT_AP_MDSRC_REQ: 261*5f748b3cSKun Lu spm_ap_mdsrc_req(set); 262*5f748b3cSKun Lu break; 263*5f748b3cSKun Lu case PLAT_AP_MDSRC_ACK: 264*5f748b3cSKun Lu ret = spm_ap_mdsrc_ack(); 265*5f748b3cSKun Lu break; 266*5f748b3cSKun Lu case PLAT_AP_IS_MD_SLEEP: 267*5f748b3cSKun Lu ret = spm_is_md_sleep(priv); 268*5f748b3cSKun Lu break; 269*5f748b3cSKun Lu case PLAT_AP_MDSRC_SETTLE: 270*5f748b3cSKun Lu if (!priv) 271*5f748b3cSKun Lu return -1; 272*5f748b3cSKun Lu *(int *)priv = AP_MDSRC_REQ_MD_26M_SETTLE; 273*5f748b3cSKun Lu break; 274*5f748b3cSKun Lu case PLAT_AP_GPUEB_PLL_CONTROL: 275*5f748b3cSKun Lu spm_ap_gpueb_pll_control(set); 276*5f748b3cSKun Lu break; 277*5f748b3cSKun Lu case PLAT_AP_GPUEB_PWR_STATUS: 278*5f748b3cSKun Lu if (!priv) 279*5f748b3cSKun Lu return -1; 280*5f748b3cSKun Lu *(uint32_t *)priv = spm_ap_gpueb_get_pwr_status(); 281*5f748b3cSKun Lu break; 282*5f748b3cSKun Lu case PLAT_AP_GPUEB_MFG0_PWR_CON: 283*5f748b3cSKun Lu if (!priv) 284*5f748b3cSKun Lu return -1; 285*5f748b3cSKun Lu *(uint32_t *)priv = spm_ap_gpueb_get_mfg0_pwr_con(); 286*5f748b3cSKun Lu break; 287*5f748b3cSKun Lu case PLAT_AP_ASSERT_SPM_IRQ: 288*5f748b3cSKun Lu mt_irq_set_pending(spm_irq_num); 289*5f748b3cSKun Lu break; 290*5f748b3cSKun Lu case PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE: 291*5f748b3cSKun Lu struct spm_lp_scen *spmlp; 292*5f748b3cSKun Lu 293*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT) 294*5f748b3cSKun Lu mt_spm_idle_generic_get_spm_lp(&spmlp); 295*5f748b3cSKun Lu #endif 296*5f748b3cSKun Lu if (!spmlp) 297*5f748b3cSKun Lu return -1; 298*5f748b3cSKun Lu __spm_set_power_control(spmlp->pwrctrl, *(uint32_t *)priv); 299*5f748b3cSKun Lu ret = __spm_wait_spm_request_ack(*(uint32_t *)priv, SPM_ACK_TIMEOUT_US); 300*5f748b3cSKun Lu break; 301*5f748b3cSKun Lu default: 302*5f748b3cSKun Lu /* not supported type */ 303*5f748b3cSKun Lu ret = -1; 304*5f748b3cSKun Lu break; 305*5f748b3cSKun Lu } 306*5f748b3cSKun Lu 307*5f748b3cSKun Lu return ret; 308*5f748b3cSKun Lu } 309*5f748b3cSKun Lu 310*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT 311*5f748b3cSKun Lu struct mt_resource_manager plat_mt8189_rm = { 312*5f748b3cSKun Lu .update = NULL, 313*5f748b3cSKun Lu .hwctrl = mt_spm_hwctrl, 314*5f748b3cSKun Lu .consts = plat_constraints, 315*5f748b3cSKun Lu }; 316*5f748b3cSKun Lu #else 317*5f748b3cSKun Lu struct mt_resource_manager plat_mt8189_rm = { 318*5f748b3cSKun Lu .hwctrl = mt_spm_hwctrl, 319*5f748b3cSKun Lu }; 320*5f748b3cSKun Lu #endif 321*5f748b3cSKun Lu 322*5f748b3cSKun Lu /* Determine for spm sw resource user */ 323*5f748b3cSKun Lu static struct mt_lp_resource_user spm_res_user; 324*5f748b3cSKun Lu 325*5f748b3cSKun Lu struct mt_lp_resource_user *get_spm_res_user(void) 326*5f748b3cSKun Lu { 327*5f748b3cSKun Lu return &spm_res_user; 328*5f748b3cSKun Lu } 329*5f748b3cSKun Lu 330*5f748b3cSKun Lu int spm_boot_init(void) 331*5f748b3cSKun Lu { 332*5f748b3cSKun Lu plat_spm_lock_init(); 333*5f748b3cSKun Lu 334*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT) 335*5f748b3cSKun Lu plat_spm_pmic_wrap_init(); 336*5f748b3cSKun Lu #endif 337*5f748b3cSKun Lu plat_spm_cond_init(); 338*5f748b3cSKun Lu 339*5f748b3cSKun Lu mt_lp_rm_register(&plat_mt8189_rm); 340*5f748b3cSKun Lu 341*5f748b3cSKun Lu /* If spm service won't run when spm not ready */ 342*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT 343*5f748b3cSKun Lu mt_lp_resource_request_manager_register(&plat_mt8189_rq); 344*5f748b3cSKun Lu mt_lp_resource_user_register("SPM", &spm_res_user); 345*5f748b3cSKun Lu mt_spm_dispatcher_init(); 346*5f748b3cSKun Lu #endif 347*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT) 348*5f748b3cSKun Lu spm_hwreq_init(); 349*5f748b3cSKun Lu #endif 350*5f748b3cSKun Lu 351*5f748b3cSKun Lu INFO("[%s:%d] - spm finished\n", __func__, __LINE__); 352*5f748b3cSKun Lu return 0; 353*5f748b3cSKun Lu } 354*5f748b3cSKun Lu MTK_ARCH_INIT(spm_boot_init); 355