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