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