1 /* 2 * Copyright (c) 2019, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* common headers */ 8 #include <arch_helpers.h> 9 #include <assert.h> 10 #include <common/debug.h> 11 #include <lib/mmio.h> 12 #include <lib/psci/psci.h> 13 #include <errno.h> 14 15 /* mediatek platform specific headers */ 16 #include <platform_def.h> 17 #include <scu.h> 18 #include <mt_gic_v3.h> 19 #include <mtk_mcdi.h> 20 #include <mtk_plat_common.h> 21 #include <mtgpio.h> 22 #include <mtspmc.h> 23 #include <plat_dcm.h> 24 #include <plat_debug.h> 25 #include <plat_params.h> 26 #include <plat_private.h> 27 #include <power_tracer.h> 28 #include <pmic.h> 29 #include <spm.h> 30 #include <spm_suspend.h> 31 #include <sspm.h> 32 #include <rtc.h> 33 34 /* Local power state for power domains in Run state. */ 35 #define MTK_LOCAL_STATE_RUN 0 36 /* Local power state for retention. */ 37 #define MTK_LOCAL_STATE_RET 1 38 /* Local power state for OFF/power-down. */ 39 #define MTK_LOCAL_STATE_OFF 2 40 41 #if PSCI_EXTENDED_STATE_ID 42 /* 43 * Macros used to parse state information from State-ID if it is using the 44 * recommended encoding for State-ID. 45 */ 46 #define MTK_LOCAL_PSTATE_WIDTH 4 47 #define MTK_LOCAL_PSTATE_MASK ((1 << MTK_LOCAL_PSTATE_WIDTH) - 1) 48 49 /* Macros to construct the composite power state */ 50 51 /* Make composite power state parameter till power level 0 */ 52 53 #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 54 (((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT)) 55 56 #else /* !PSCI_EXTENDED_STATE_ID */ 57 58 #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 59 (((lvl0_state) << PSTATE_ID_SHIFT) | \ 60 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ 61 ((type) << PSTATE_TYPE_SHIFT)) 62 63 #endif /* PSCI_EXTENDED_STATE_ID */ 64 65 /* Make composite power state parameter till power level 1 */ 66 #define mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ 67 (((lvl1_state) << MTK_LOCAL_PSTATE_WIDTH) | \ 68 mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) 69 70 /* Make composite power state parameter till power level 2 */ 71 #define mtk_make_pwrstate_lvl2( \ 72 lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \ 73 (((lvl2_state) << (MTK_LOCAL_PSTATE_WIDTH * 2)) | \ 74 mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type)) 75 76 #define MTK_PWR_LVL0 0 77 #define MTK_PWR_LVL1 1 78 #define MTK_PWR_LVL2 2 79 80 /* Macros to read the MTK power domain state */ 81 #define MTK_CORE_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL0] 82 #define MTK_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL1] 83 #define MTK_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) ? \ 84 (state)->pwr_domain_state[MTK_PWR_LVL2] : 0) 85 86 #if PSCI_EXTENDED_STATE_ID 87 /* 88 * The table storing the valid idle power states. Ensure that the 89 * array entries are populated in ascending order of state-id to 90 * enable us to use binary search during power state validation. 91 * The table must be terminated by a NULL entry. 92 */ 93 const unsigned int mtk_pm_idle_states[] = { 94 /* State-id - 0x001 */ 95 mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, 96 MTK_LOCAL_STATE_RET, MTK_PWR_LVL0, PSTATE_TYPE_STANDBY), 97 /* State-id - 0x002 */ 98 mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, 99 MTK_LOCAL_STATE_OFF, MTK_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 100 /* State-id - 0x022 */ 101 mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF, 102 MTK_LOCAL_STATE_OFF, MTK_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 103 #if PLAT_MAX_PWR_LVL > MTK_PWR_LVL1 104 /* State-id - 0x222 */ 105 mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, 106 MTK_LOCAL_STATE_OFF, MTK_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 107 #endif 108 0, 109 }; 110 #endif 111 112 #define CPU_IDX(cluster, cpu) ((cluster << 2) + cpu) 113 #define ON true 114 #define OFF false 115 116 /* Pause MCDI when CPU hotplug */ 117 static bool HP_SSPM_PAUSE; 118 /* CPU Hotplug by SSPM */ 119 static bool HP_SSPM_CTRL = true; 120 /* Turn off cluster when CPU hotplug off */ 121 static bool HP_CLUSTER_OFF = true; 122 /* Turn off cluster when CPU MCDI off */ 123 static bool MCDI_C2 = true; 124 /* Enable MCDI */ 125 static bool MCDI_SSPM = true; 126 127 static uintptr_t secure_entrypoint; 128 129 static void mp1_L2_desel_config(void) 130 { 131 mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820); 132 133 dsb(); 134 } 135 136 static bool clst_single_pwr(int cluster, int cpu) 137 { 138 uint32_t cpu_mask[2] = {0x00001e00, 0x000f0000}; 139 uint32_t cpu_pwr_bit[] = {9, 10, 11, 12, 16, 17, 18, 19}; 140 int my_idx = (cluster << 2) + cpu; 141 uint32_t pwr_stat = mmio_read_32(0x10006180); 142 143 return !(pwr_stat & (cpu_mask[cluster] & ~BIT(cpu_pwr_bit[my_idx]))); 144 } 145 146 static bool clst_single_on(int cluster, int cpu) 147 { 148 uint32_t cpu_mask[2] = {0x0f, 0xf0}; 149 int my_idx = (cluster << 2) + cpu; 150 uint32_t on_stat = mcdi_avail_cpu_mask_read(); 151 152 return !(on_stat & (cpu_mask[cluster] & ~BIT(my_idx))); 153 } 154 155 static void plat_cluster_pwrdwn_common(uint64_t mpidr, int cluster) 156 { 157 if (cluster > 0) 158 mt_gic_sync_dcm_enable(); 159 160 /* Disable coherency */ 161 plat_mtk_cci_disable(); 162 disable_scu(mpidr); 163 } 164 165 static void plat_cluster_pwron_common(uint64_t mpidr, int cluster) 166 { 167 if (cluster > 0) { 168 l2c_parity_check_setup(); 169 circular_buffer_setup(); 170 mp1_L2_desel_config(); 171 mt_gic_sync_dcm_disable(); 172 } 173 174 /* Enable coherency */ 175 enable_scu(mpidr); 176 plat_mtk_cci_enable(); 177 /* Enable big core dcm */ 178 plat_dcm_restore_cluster_on(mpidr); 179 /* Enable rgu dcm */ 180 plat_dcm_rgu_enable(); 181 } 182 183 static void plat_cpu_standby(plat_local_state_t cpu_state) 184 { 185 unsigned int scr; 186 187 scr = read_scr_el3(); 188 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 189 190 isb(); 191 dsb(); 192 wfi(); 193 194 write_scr_el3(scr); 195 } 196 197 static void mcdi_ctrl_before_hotplug_on(int cluster, int cpu) 198 { 199 if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM) { 200 mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), OFF); 201 mcdi_pause_set(cluster, CPU_IDX(cluster, cpu), ON); 202 } 203 } 204 205 static void mcdi_ctrl_before_hotplug_off(int cluster, int cpu, bool cluster_off) 206 { 207 if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM) 208 mcdi_pause_set(cluster_off ? cluster : -1, 209 CPU_IDX(cluster, cpu), OFF); 210 } 211 212 static void mcdi_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off) 213 { 214 if (MCDI_SSPM) { 215 sspm_set_bootaddr(secure_entrypoint); 216 217 sspm_standbywfi_irq_enable(CPU_IDX(cluster, cpu)); 218 219 if (cluster_off) 220 sspm_cluster_pwr_off_notify(cluster); 221 else 222 sspm_cluster_pwr_on_notify(cluster); 223 } 224 } 225 226 static void mcdi_ctrl_suspend(void) 227 { 228 if (MCDI_SSPM) 229 mcdi_pause(); 230 } 231 232 static void mcdi_ctrl_resume(void) 233 { 234 if (MCDI_SSPM) 235 mcdi_unpause(); 236 } 237 238 static void hotplug_ctrl_cluster_on(int cluster, int cpu) 239 { 240 if (HP_SSPM_CTRL && MCDI_SSPM) { 241 mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), OFF); 242 mcdi_hotplug_set(cluster, -1, ON); 243 mcdi_hotplug_wait_ack(cluster, -1, ON); 244 } else { 245 /* power on cluster */ 246 if (!spm_get_cluster_powerstate(cluster)) 247 spm_poweron_cluster(cluster); 248 } 249 } 250 251 static void hotplug_ctrl_cpu_on(int cluster, int cpu) 252 { 253 if (HP_SSPM_CTRL && MCDI_SSPM) 254 mcdi_hotplug_set(cluster, CPU_IDX(cluster, cpu), ON); 255 else 256 spm_poweron_cpu(cluster, cpu); 257 } 258 259 static void hotplug_ctrl_cpu_on_finish(int cluster, int cpu) 260 { 261 spm_disable_cpu_auto_off(cluster, cpu); 262 263 if (HP_SSPM_CTRL && MCDI_SSPM) 264 mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), ON); 265 else if (HP_SSPM_PAUSE && MCDI_SSPM) 266 mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), ON); 267 268 mcdi_avail_cpu_mask_set(BIT(CPU_IDX(cluster, cpu))); 269 } 270 271 static void hotplug_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off) 272 { 273 mcdi_avail_cpu_mask_clr(BIT(CPU_IDX(cluster, cpu))); 274 275 if (HP_SSPM_CTRL && MCDI_SSPM) { 276 mcdi_hotplug_set(cluster_off ? cluster : -1, 277 CPU_IDX(cluster, cpu), OFF); 278 } else { 279 spm_enable_cpu_auto_off(cluster, cpu); 280 281 if (cluster_off) 282 spm_enable_cluster_auto_off(cluster); 283 284 spm_set_cpu_power_off(cluster, cpu); 285 } 286 } 287 288 static int plat_mtk_power_domain_on(unsigned long mpidr) 289 { 290 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 291 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 292 293 mcdi_ctrl_before_hotplug_on(cluster, cpu); 294 hotplug_ctrl_cluster_on(cluster, cpu); 295 296 /* init cpu reset arch as AARCH64 */ 297 mcucfg_init_archstate(cluster, cpu, 1); 298 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 299 300 hotplug_ctrl_cpu_on(cluster, cpu); 301 302 return PSCI_E_SUCCESS; 303 } 304 305 static void plat_mtk_power_domain_off(const psci_power_state_t *state) 306 { 307 uint64_t mpidr = read_mpidr(); 308 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 309 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 310 const plat_local_state_t *pds = state->pwr_domain_state; 311 bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); 312 bool cluster_off = (HP_CLUSTER_OFF && afflvl1 && 313 clst_single_on(cluster, cpu)); 314 315 mt_gic_cpuif_disable(); 316 317 if (cluster_off) 318 plat_cluster_pwrdwn_common(mpidr, cluster); 319 320 mcdi_ctrl_before_hotplug_off(cluster, cpu, cluster_off); 321 hotplug_ctrl_cluster_cpu_off(cluster, cpu, cluster_off); 322 } 323 324 static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state) 325 { 326 uint64_t mpidr = read_mpidr(); 327 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 328 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 329 const plat_local_state_t *pds = state->pwr_domain_state; 330 bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); 331 332 if (afflvl1) 333 plat_cluster_pwron_common(mpidr, cluster); 334 335 mt_gic_pcpu_init(); 336 mt_gic_cpuif_enable(); 337 338 hotplug_ctrl_cpu_on_finish(cluster, cpu); 339 } 340 341 static void plat_mtk_power_domain_suspend(const psci_power_state_t *state) 342 { 343 uint64_t mpidr = read_mpidr(); 344 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 345 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 346 const plat_local_state_t *pds = state->pwr_domain_state; 347 bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); 348 bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF); 349 bool cluster_off = MCDI_C2 && afflvl1 && clst_single_pwr(cluster, cpu); 350 351 /* init cpu reset arch as AARCH64 */ 352 mcucfg_init_archstate(cluster, cpu, 1); 353 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 354 355 mt_gic_cpuif_disable(); 356 mt_gic_irq_save(); 357 plat_dcm_mcsi_a_backup(); 358 359 if (cluster_off || afflvl2) 360 plat_cluster_pwrdwn_common(mpidr, cluster); 361 362 if (afflvl2) { 363 spm_data_t spm_d = { .cmd = SPM_SUSPEND }; 364 uint32_t *d = (uint32_t *)&spm_d; 365 uint32_t l = sizeof(spm_d) / sizeof(uint32_t); 366 367 mcdi_ctrl_suspend(); 368 369 spm_set_bootaddr(secure_entrypoint); 370 371 if (MCDI_SSPM) 372 sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d); 373 374 spm_system_suspend(); 375 376 if (MCDI_SSPM) 377 while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l)) 378 ; 379 } else { 380 mcdi_ctrl_cluster_cpu_off(cluster, cpu, cluster_off); 381 } 382 } 383 384 static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state) 385 { 386 uint64_t mpidr = read_mpidr(); 387 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 388 const plat_local_state_t *pds = state->pwr_domain_state; 389 bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF); 390 391 if (afflvl2) { 392 spm_data_t spm_d = { .cmd = SPM_RESUME }; 393 uint32_t *d = (uint32_t *)&spm_d; 394 uint32_t l = sizeof(spm_d) / sizeof(uint32_t); 395 396 mt_gic_init(); 397 mt_gic_irq_restore(); 398 mmio_write_32(EMI_WFIFO, 0xf); 399 400 if (MCDI_SSPM) 401 sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d); 402 403 spm_system_suspend_finish(); 404 405 if (MCDI_SSPM) 406 while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l)) 407 ; 408 409 mcdi_ctrl_resume(); 410 } 411 412 plat_cluster_pwron_common(mpidr, cluster); 413 414 plat_dcm_mcsi_a_restore(); 415 } 416 417 #if PSCI_EXTENDED_STATE_ID 418 419 static int plat_mtk_validate_power_state(unsigned int power_state, 420 psci_power_state_t *req_state) 421 { 422 unsigned int state_id; 423 int i; 424 425 assert(req_state); 426 427 if (!MCDI_SSPM) 428 return PSCI_E_INVALID_PARAMS; 429 430 /* 431 * Currently we are using a linear search for finding the matching 432 * entry in the idle power state array. This can be made a binary 433 * search if the number of entries justify the additional complexity. 434 */ 435 for (i = 0; !!mtk_pm_idle_states[i]; i++) { 436 if (power_state == mtk_pm_idle_states[i]) 437 break; 438 } 439 440 /* Return error if entry not found in the idle state array */ 441 if (!mtk_pm_idle_states[i]) 442 return PSCI_E_INVALID_PARAMS; 443 444 i = 0; 445 state_id = psci_get_pstate_id(power_state); 446 447 /* Parse the State ID and populate the state info parameter */ 448 while (state_id) { 449 req_state->pwr_domain_state[i++] = state_id & 450 MTK_LOCAL_PSTATE_MASK; 451 state_id >>= MTK_LOCAL_PSTATE_WIDTH; 452 } 453 454 return PSCI_E_SUCCESS; 455 } 456 457 #else /* if !PSCI_EXTENDED_STATE_ID */ 458 459 static int plat_mtk_validate_power_state(unsigned int power_state, 460 psci_power_state_t *req_state) 461 { 462 int pstate = psci_get_pstate_type(power_state); 463 int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 464 int i; 465 466 assert(req_state); 467 468 if (pwr_lvl > PLAT_MAX_PWR_LVL) 469 return PSCI_E_INVALID_PARAMS; 470 471 /* Sanity check the requested state */ 472 if (pstate == PSTATE_TYPE_STANDBY) { 473 /* 474 * It's possible to enter standby only on power level 0 475 * Ignore any other power level. 476 */ 477 if (pwr_lvl != 0) 478 return PSCI_E_INVALID_PARAMS; 479 480 req_state->pwr_domain_state[MTK_PWR_LVL0] = MTK_LOCAL_STATE_RET; 481 } else if (!MCDI_SSPM) { 482 return PSCI_E_INVALID_PARAMS; 483 } else { 484 for (i = 0; i <= pwr_lvl; i++) 485 req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; 486 } 487 488 return PSCI_E_SUCCESS; 489 } 490 491 #endif /* PSCI_EXTENDED_STATE_ID */ 492 493 /******************************************************************************* 494 * MTK handlers to shutdown/reboot the system 495 ******************************************************************************/ 496 static void __dead2 plat_mtk_system_off(void) 497 { 498 INFO("MTK System Off\n"); 499 500 rtc_power_off_sequence(); 501 wk_pmic_enable_sdn_delay(); 502 pmic_power_off(); 503 504 wfi(); 505 ERROR("MTK System Off: operation not handled.\n"); 506 panic(); 507 } 508 509 static void __dead2 plat_mtk_system_reset(void) 510 { 511 struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); 512 513 INFO("MTK System Reset\n"); 514 515 mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity); 516 517 wfi(); 518 ERROR("MTK System Reset: operation not handled.\n"); 519 panic(); 520 } 521 522 static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state) 523 { 524 assert(PLAT_MAX_PWR_LVL >= 2); 525 526 for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 527 req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; 528 } 529 530 /******************************************************************************* 531 * MTK_platform handler called when an affinity instance is about to be turned 532 * on. The level and mpidr determine the affinity instance. 533 ******************************************************************************/ 534 static const plat_psci_ops_t plat_plat_pm_ops = { 535 .cpu_standby = plat_cpu_standby, 536 .pwr_domain_on = plat_mtk_power_domain_on, 537 .pwr_domain_on_finish = plat_mtk_power_domain_on_finish, 538 .pwr_domain_off = plat_mtk_power_domain_off, 539 .pwr_domain_suspend = plat_mtk_power_domain_suspend, 540 .pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish, 541 .system_off = plat_mtk_system_off, 542 .system_reset = plat_mtk_system_reset, 543 .validate_power_state = plat_mtk_validate_power_state, 544 .get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state, 545 }; 546 547 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 548 const plat_psci_ops_t **psci_ops) 549 { 550 *psci_ops = &plat_plat_pm_ops; 551 secure_entrypoint = sec_entrypoint; 552 553 if (!check_mcdi_ctl_stat()) { 554 HP_SSPM_CTRL = false; 555 MCDI_SSPM = false; 556 } 557 558 return 0; 559 } 560