1 /* 2 * Copyright (c) 2025, Mediatek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stddef.h> 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <arch.h> 13 #include <common/debug.h> 14 #include <drivers/console.h> 15 #include <drivers/delay_timer.h> 16 #include <drivers/gpio.h> 17 #include <lib/bakery_lock.h> 18 #include <lib/mmio.h> 19 #include <lib/utils_def.h> 20 #include <platform_def.h> 21 22 #include <constraints/mt_spm_rc_api.h> 23 #include <constraints/mt_spm_rc_internal.h> 24 #include <drivers/spm/mt_spm_resource_req.h> 25 #include <lib/mtk_init/mtk_init.h> 26 #include <lib/pm/mtk_pm.h> 27 #include <lpm_v2/mt_lp_rm.h> 28 #include <lpm_v2/mt_lp_rqm.h> 29 #include <lpm_v2/mt_lpm_smc.h> 30 #include <mt_plat_spm_setting.h> 31 #include <mt_spm.h> 32 #include <mt_spm_common.h> 33 #include <mt_spm_conservation.h> 34 #include <mt_spm_constraint.h> 35 #include <mt_spm_dispatcher.h> 36 #include <mt_spm_hwreq.h> 37 #include <mt_spm_idle.h> 38 #include <mt_spm_internal.h> 39 #include <mt_spm_reg.h> 40 #include <mt_spm_suspend.h> 41 #include <mtk_mmap_pool.h> 42 #include <sleep_def.h> 43 44 #ifdef MT_SPM_USING_BAKERY_LOCK 45 DEFINE_BAKERY_LOCK(spm_lock); 46 #define plat_spm_lock_init() \ 47 bakery_lock_init(&spm_lock) 48 #else 49 spinlock_t spm_lock; 50 #define plat_spm_lock_init() 51 #endif 52 53 static uint32_t spm_irq_num; 54 55 void spm_set_sysclk_settle(void) 56 { 57 uint32_t settle; 58 59 mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE); 60 settle = mmio_read_32(SPM_CLK_SETTLE); 61 62 INFO("md_settle = %u, settle = %u\n", SPM_SYSCLK_SETTLE, settle); 63 } 64 65 void spm_set_irq_num(uint32_t num) 66 { 67 spm_irq_num = num; 68 } 69 70 void spm_irq0_handler(uint64_t x1, uint64_t x2) 71 { 72 if (x2 == 0) { 73 mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM); 74 mmio_write_32(SPM_IRQ_STA, x1); 75 mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT0); 76 } 77 } 78 79 static int spm_ap_mdsrc_ack(void) 80 { 81 int ack, md_state = 0; 82 83 /* Check ap_mdsrc_ack = 1'b1, for md internal resource on ack */ 84 ack = !!(mmio_read_32(AP_MDSRC_REQ) & AP_MDSMSRC_ACK_LSB); 85 86 if (!ack) { 87 /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */ 88 md_state = !!(mmio_read_32(SPM_REQ_STA_10) 89 & MD_APSRC_REQ_LSB); 90 91 ERROR("[SPM] error: md_sleep = %d\n", md_state); 92 ERROR("%s can not get AP_MDSRC_ACK\n", __func__); 93 return -1; 94 } 95 return 0; 96 } 97 98 static void spm_ap_mdsrc_req(int set) 99 { 100 spm_lock_get(); 101 102 if (set) 103 mmio_setbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB); 104 else 105 mmio_clrbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB); 106 107 spm_lock_release(); 108 } 109 110 static int spm_is_md_sleep(void *priv) 111 { 112 int md_state = 0; 113 int *sleep = (int *)priv; 114 115 if (!priv) 116 return -1; 117 118 /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */ 119 md_state = !!(mmio_read_32(SPM_REQ_STA_10) 120 & MD_APSRC_REQ_LSB); 121 122 if (md_state == 0) 123 *sleep = 1; 124 else 125 *sleep = 0; 126 127 return 0; 128 } 129 130 static void spm_ap_gpueb_pll_control(int set) 131 { 132 spm_lock_get(); 133 134 if (set) 135 mmio_setbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB); 136 else 137 mmio_clrbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB); 138 139 spm_lock_release(); 140 } 141 142 static uint32_t spm_ap_gpueb_get_pwr_status(void) 143 { 144 uint32_t ret; 145 146 ret = mmio_read_32(XPU_PWR_STATUS); 147 148 return ret; 149 } 150 151 static uint32_t spm_ap_gpueb_get_mfg0_pwr_con(void) 152 { 153 uint32_t ret; 154 155 ret = mmio_read_32(MFG0_PWR_CON); 156 157 return ret; 158 } 159 160 #ifndef MTK_PLAT_SPM_UNSUPPORT 161 struct mt_lp_res_req rq_xo_fpm = { 162 .res_id = MT_LP_RQ_XO_FPM, 163 .res_rq = MT_SPM_XO_FPM, 164 .res_usage = 0, 165 }; 166 167 struct mt_lp_res_req rq_26m = { 168 .res_id = MT_LP_RQ_26M, 169 .res_rq = MT_SPM_26M, 170 .res_usage = 0, 171 }; 172 173 struct mt_lp_res_req rq_infra = { 174 .res_id = MT_LP_RQ_INFRA, 175 .res_rq = MT_SPM_INFRA, 176 .res_usage = 0, 177 }; 178 179 struct mt_lp_res_req rq_syspll = { 180 .res_id = MT_LP_RQ_SYSPLL, 181 .res_rq = MT_SPM_SYSPLL, 182 .res_usage = 0, 183 }; 184 185 struct mt_lp_res_req rq_dram_s0 = { 186 .res_id = MT_LP_RQ_DRAM, 187 .res_rq = MT_SPM_DRAM_S0, 188 .res_usage = 0, 189 }; 190 191 struct mt_lp_res_req rq_dram_s1 = { 192 .res_id = MT_LP_RQ_DRAM, 193 .res_rq = MT_SPM_DRAM_S1, 194 .res_usage = 0, 195 }; 196 197 struct mt_lp_res_req rq_vcore = { 198 .res_id = MT_LP_RQ_VCORE, 199 .res_rq = MT_SPM_VCORE, 200 .res_usage = 0, 201 }; 202 203 struct mt_lp_res_req rq_emi = { 204 .res_id = MT_LP_RQ_EMI, 205 .res_rq = MT_SPM_EMI, 206 .res_usage = 0, 207 }; 208 209 struct mt_lp_res_req rq_pmic = { 210 .res_id = MT_LP_RQ_PMIC, 211 .res_rq = MT_SPM_PMIC, 212 .res_usage = 0, 213 }; 214 215 struct mt_lp_res_req *spm_resources[] = { 216 &rq_xo_fpm, 217 &rq_26m, 218 &rq_infra, 219 &rq_syspll, 220 &rq_dram_s0, 221 &rq_dram_s1, 222 &rq_vcore, 223 &rq_emi, 224 &rq_pmic, 225 NULL, 226 }; 227 228 struct mt_resource_req_manager plat_mt8196_rq = { 229 .res = spm_resources, 230 }; 231 232 struct mt_resource_constraint plat_constraint_vcore = { 233 .is_valid = spm_is_valid_rc_vcore, 234 .update = spm_update_rc_vcore, 235 .allow = spm_allow_rc_vcore, 236 .run = spm_run_rc_vcore, 237 .reset = spm_reset_rc_vcore, 238 .get_status = spm_get_status_rc_vcore, 239 }; 240 241 struct mt_resource_constraint plat_constraint_bus26m = { 242 .is_valid = spm_is_valid_rc_bus26m, 243 .update = spm_update_rc_bus26m, 244 .allow = spm_allow_rc_bus26m, 245 .run = spm_run_rc_bus26m, 246 .reset = spm_reset_rc_bus26m, 247 .get_status = spm_get_status_rc_bus26m, 248 }; 249 250 struct mt_resource_constraint plat_constraint_syspll = { 251 .is_valid = spm_is_valid_rc_syspll, 252 .update = spm_update_rc_syspll, 253 .allow = spm_allow_rc_syspll, 254 .run = spm_run_rc_syspll, 255 .reset = spm_reset_rc_syspll, 256 .get_status = spm_get_status_rc_syspll, 257 }; 258 259 struct mt_resource_constraint *plat_constraints[] = { 260 &plat_constraint_vcore, 261 &plat_constraint_bus26m, 262 &plat_constraint_syspll, 263 NULL, 264 }; 265 #endif 266 267 int mt_spm_hwctrl(uint32_t type, int set, void *priv) 268 { 269 int ret = 0; 270 271 if (type == PLAT_AP_MDSRC_REQ) { 272 spm_ap_mdsrc_req(set); 273 } else if (type == PLAT_AP_MDSRC_ACK) { 274 ret = spm_ap_mdsrc_ack(); 275 } else if (type == PLAT_AP_IS_MD_SLEEP) { 276 ret = spm_is_md_sleep(priv); 277 } else if (type == PLAT_AP_MDSRC_SETTLE) { 278 if (!priv) 279 return -1; 280 *(int *)priv = AP_MDSRC_REQ_MD_26M_SETTLE; 281 } else if (type == PLAT_AP_GPUEB_PLL_CONTROL) { 282 spm_ap_gpueb_pll_control(set); 283 } else if (type == PLAT_AP_GPUEB_PWR_STATUS) { 284 if (!priv) 285 return -1; 286 *(uint32_t *)priv = spm_ap_gpueb_get_pwr_status(); 287 } else if (type == PLAT_AP_GPUEB_MFG0_PWR_CON) { 288 if (!priv) 289 return -1; 290 *(uint32_t *)priv = spm_ap_gpueb_get_mfg0_pwr_con(); 291 } else if (type == PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE) { 292 struct spm_lp_scen *spmlp = NULL; 293 294 #ifdef MT_SPM_COMMON_SODI_SUPPORT 295 mt_spm_common_sodi_get_spm_lp(&spmlp); 296 #else 297 #if defined(MT_SPM_FEATURE_SUPPORT) 298 mt_spm_idle_generic_get_spm_lp(&spmlp); 299 #endif 300 #endif 301 if (!spmlp) 302 return -1; 303 __spm_set_power_control(spmlp->pwrctrl, *(uint32_t *)priv); 304 ret = __spm_wait_spm_request_ack(*(uint32_t *)priv, 305 SPM_ACK_TIMEOUT_US); 306 } else if (type == PLAT_AP_SPM_WDT_TRIGGER) { 307 mmio_write_32(PCM_WDT_VAL, 0x1); 308 mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | 309 REG_PCM_WDT_EN_LSB | REG_PCM_WDT_WAKE_LSB); 310 } else { 311 /* Not supported type */ 312 return -1; 313 } 314 315 return ret; 316 } 317 318 #ifndef MTK_PLAT_SPM_UNSUPPORT 319 struct mt_resource_manager plat_mt8196_rm = { 320 .update = NULL, 321 .hwctrl = mt_spm_hwctrl, 322 .consts = plat_constraints, 323 }; 324 #else 325 struct mt_resource_manager plat_mt8196_rm = { 326 .hwctrl = mt_spm_hwctrl, 327 }; 328 #endif 329 330 /* Determine for spm sw resource user */ 331 static struct mt_lp_resource_user spm_res_user; 332 333 struct mt_lp_resource_user *get_spm_res_user(void) 334 { 335 return &spm_res_user; 336 } 337 338 #ifdef MT_SPM_COMMON_SODI_SUPPORT 339 int mt_spm_common_sodi_get_spm_pcm_flag(uint32_t *lp, uint32_t idx) 340 { 341 struct spm_lp_scen *spmlp; 342 struct pwr_ctrl *pwrctrl; 343 344 mt_spm_common_sodi_get_spm_lp(&spmlp); 345 346 pwrctrl = spmlp->pwrctrl; 347 348 if (!lp || idx > 1) 349 return -1; 350 351 switch (idx) { 352 case 0: 353 *lp = pwrctrl->pcm_flags; 354 break; 355 case 1: 356 *lp = pwrctrl->pcm_flags; 357 break; 358 default: 359 return -1; 360 } 361 return 0; 362 } 363 364 void mt_spm_common_sodi_en(bool en) 365 { 366 struct spm_lp_scen *spmlp; 367 struct pwr_ctrl *pwrctrl; 368 369 mt_spm_common_sodi_get_spm_lp(&spmlp); 370 pwrctrl = spmlp->pwrctrl; 371 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT) 372 __spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags, 373 &__spm_vcorefs.pwrctrl->pcm_flags); 374 #endif 375 if (en) 376 pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_COMMON_SODI5; 377 else 378 pwrctrl->pcm_flags &= (~SPM_FLAG_ENABLE_COMMON_SODI5); 379 380 /* Set PCM flags */ 381 __spm_set_pcm_flags(pwrctrl); 382 383 __spm_send_cpu_wakeup_event(); 384 } 385 386 int mt_spm_common_sodi_get_spm_lp(struct spm_lp_scen **lp) 387 { 388 if (!lp) 389 return -1; 390 391 *lp = &__spm_common_sodi; 392 return 0; 393 } 394 395 void mt_spm_set_common_sodi_pwrctr(void) 396 { 397 struct resource_req_status common_sodi_spm_resource_req = { 398 .id = MT_LP_RQ_ID_ALL_USAGE, 399 .val = 0, 400 }; 401 struct spm_lp_scen *spmlp; 402 403 mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE, 404 &common_sodi_spm_resource_req); 405 mt_spm_common_sodi_get_spm_lp(&spmlp); 406 407 __spm_set_power_control(spmlp->pwrctrl, 408 common_sodi_spm_resource_req.val); 409 } 410 411 void mt_spm_set_common_sodi_pcm_flags(void) 412 { 413 struct spm_lp_scen *spmlp; 414 struct pwr_ctrl *pwrctrl; 415 416 mt_spm_common_sodi_get_spm_lp(&spmlp); 417 pwrctrl = spmlp->pwrctrl; 418 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT) 419 /* Set PCM flags */ 420 __spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags, 421 &__spm_vcorefs.pwrctrl->pcm_flags); 422 #endif 423 __spm_set_pcm_flags(pwrctrl); 424 425 __spm_send_cpu_wakeup_event(); 426 427 } 428 #endif 429 430 int spm_boot_init(void) 431 { 432 plat_spm_lock_init(); 433 434 #if defined(MT_SPM_FEATURE_SUPPORT) 435 plat_spm_pmic_wrap_init(); 436 #endif 437 mt_lp_rm_register(&plat_mt8196_rm); 438 439 #ifndef MTK_PLAT_SPM_UNSUPPORT 440 mt_lp_resource_request_manager_register(&plat_mt8196_rq); 441 mt_lp_resource_user_register("SPM", &spm_res_user); 442 mt_spm_dispatcher_init(); 443 #endif 444 #if defined(MT_SPM_FEATURE_SUPPORT) 445 spm_hwreq_init(); 446 #endif 447 spm_irq_num = 0xFFFFFFFF; 448 449 INFO("[%s], PC = 0x%x\n", __func__, mmio_read_32(MD32PCM_PC)); 450 return 0; 451 } 452 MTK_PLAT_SETUP_1_INIT(spm_boot_init); 453