13fa9dec4Skenny liang /* 27352f329Skenny liang * Copyright (c) 2019, MediaTek Inc. All rights reserved. 33fa9dec4Skenny liang * 43fa9dec4Skenny liang * SPDX-License-Identifier: BSD-3-Clause 53fa9dec4Skenny liang */ 63fa9dec4Skenny liang 73fa9dec4Skenny liang /* common headers */ 83fa9dec4Skenny liang #include <arch_helpers.h> 93fa9dec4Skenny liang #include <assert.h> 103fa9dec4Skenny liang #include <common/debug.h> 113fa9dec4Skenny liang #include <lib/mmio.h> 123fa9dec4Skenny liang #include <lib/psci/psci.h> 133fa9dec4Skenny liang #include <errno.h> 143fa9dec4Skenny liang 153fa9dec4Skenny liang /* mediatek platform specific headers */ 163fa9dec4Skenny liang #include <platform_def.h> 173fa9dec4Skenny liang #include <scu.h> 187352f329Skenny liang #include <mt_gic_v3.h> 193fa9dec4Skenny liang #include <mtk_plat_common.h> 203d91c9c3Skenny liang #include <mtgpio.h> 217352f329Skenny liang #include <mtspmc.h> 227352f329Skenny liang #include <plat_dcm.h> 237352f329Skenny liang #include <plat_debug.h> 243d91c9c3Skenny liang #include <plat_params.h> 253fa9dec4Skenny liang #include <plat_private.h> 263d91c9c3Skenny liang #include <power_tracer.h> 27e977b4dbSkenny liang #include <pmic.h> 28*3c25ba44Skenny liang #include <spm.h> 29*3c25ba44Skenny liang #include <spm_suspend.h> 30e977b4dbSkenny liang #include <rtc.h> 313fa9dec4Skenny liang 327352f329Skenny liang #define MTK_LOCAL_STATE_OFF 2 337352f329Skenny liang 347352f329Skenny liang static uintptr_t secure_entrypoint; 357352f329Skenny liang 367352f329Skenny liang static void mp1_L2_desel_config(void) 377352f329Skenny liang { 387352f329Skenny liang mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820); 397352f329Skenny liang 407352f329Skenny liang dsb(); 417352f329Skenny liang } 427352f329Skenny liang 437352f329Skenny liang static int plat_mtk_power_domain_on(unsigned long mpidr) 447352f329Skenny liang { 457352f329Skenny liang int cpu = MPIDR_AFFLVL0_VAL(mpidr); 467352f329Skenny liang int cluster = MPIDR_AFFLVL1_VAL(mpidr); 477352f329Skenny liang 487352f329Skenny liang INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n", 497352f329Skenny liang __func__, __LINE__, mpidr, cluster, cpu); 507352f329Skenny liang 517352f329Skenny liang /* power on cluster */ 527352f329Skenny liang if (!spm_get_cluster_powerstate(cluster)) { 537352f329Skenny liang spm_poweron_cluster(cluster); 547352f329Skenny liang if (cluster == 1) { 557352f329Skenny liang l2c_parity_check_setup(); 567352f329Skenny liang circular_buffer_setup(); 577352f329Skenny liang mp1_L2_desel_config(); 587352f329Skenny liang mt_gic_sync_dcm_disable(); 597352f329Skenny liang } 607352f329Skenny liang } 617352f329Skenny liang 627352f329Skenny liang /* init cpu reset arch as AARCH64 */ 637352f329Skenny liang mcucfg_init_archstate(cluster, cpu, 1); 647352f329Skenny liang mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 657352f329Skenny liang 667352f329Skenny liang spm_poweron_cpu(cluster, cpu); 677352f329Skenny liang 687352f329Skenny liang return PSCI_E_SUCCESS; 697352f329Skenny liang } 707352f329Skenny liang 717352f329Skenny liang static void plat_mtk_power_domain_off(const psci_power_state_t *state) 727352f329Skenny liang { 737352f329Skenny liang uint64_t mpidr = read_mpidr(); 747352f329Skenny liang int cpu = MPIDR_AFFLVL0_VAL(mpidr); 757352f329Skenny liang int cluster = MPIDR_AFFLVL1_VAL(mpidr); 767352f329Skenny liang 777352f329Skenny liang INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 787352f329Skenny liang 797352f329Skenny liang /* Prevent interrupts from spuriously waking up this cpu */ 807352f329Skenny liang mt_gic_cpuif_disable(); 817352f329Skenny liang 827352f329Skenny liang spm_enable_cpu_auto_off(cluster, cpu); 837352f329Skenny liang 847352f329Skenny liang if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 857352f329Skenny liang if (cluster == 1) 867352f329Skenny liang mt_gic_sync_dcm_enable(); 877352f329Skenny liang 887352f329Skenny liang plat_mtk_cci_disable(); 897352f329Skenny liang spm_enable_cluster_auto_off(cluster); 907352f329Skenny liang } 917352f329Skenny liang 927352f329Skenny liang spm_set_cpu_power_off(cluster, cpu); 937352f329Skenny liang } 947352f329Skenny liang 957352f329Skenny liang static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state) 967352f329Skenny liang { 977352f329Skenny liang uint64_t mpidr = read_mpidr(); 987352f329Skenny liang int cpu = MPIDR_AFFLVL0_VAL(mpidr); 997352f329Skenny liang int cluster = MPIDR_AFFLVL1_VAL(mpidr); 1007352f329Skenny liang 1017352f329Skenny liang INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 1027352f329Skenny liang 1037352f329Skenny liang assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF); 1047352f329Skenny liang 1057352f329Skenny liang if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 1067352f329Skenny liang enable_scu(mpidr); 1077352f329Skenny liang 1087352f329Skenny liang /* Enable coherency if this cluster was off */ 1097352f329Skenny liang plat_mtk_cci_enable(); 1107352f329Skenny liang /* Enable big core dcm if this cluster was on */ 1117352f329Skenny liang plat_dcm_restore_cluster_on(mpidr); 1127352f329Skenny liang /* Enable rgu dcm if this cluster was off */ 1137352f329Skenny liang plat_dcm_rgu_enable(); 1147352f329Skenny liang } 1157352f329Skenny liang 1167352f329Skenny liang spm_disable_cpu_auto_off(cluster, cpu); 1177352f329Skenny liang 1187352f329Skenny liang /* Enable the gic cpu interface */ 1197352f329Skenny liang mt_gic_pcpu_init(); 1207352f329Skenny liang mt_gic_cpuif_enable(); 1217352f329Skenny liang } 1227352f329Skenny liang 1233fa9dec4Skenny liang /******************************************************************************* 124e977b4dbSkenny liang * MTK handlers to shutdown/reboot the system 125e977b4dbSkenny liang ******************************************************************************/ 126e977b4dbSkenny liang static void __dead2 plat_mtk_system_off(void) 127e977b4dbSkenny liang { 128e977b4dbSkenny liang INFO("MTK System Off\n"); 129e977b4dbSkenny liang 130e977b4dbSkenny liang rtc_power_off_sequence(); 131e977b4dbSkenny liang wk_pmic_enable_sdn_delay(); 132e977b4dbSkenny liang pmic_power_off(); 133e977b4dbSkenny liang 134e977b4dbSkenny liang wfi(); 135e977b4dbSkenny liang ERROR("MTK System Off: operation not handled.\n"); 136e977b4dbSkenny liang panic(); 137e977b4dbSkenny liang } 138e977b4dbSkenny liang 1393d91c9c3Skenny liang static void __dead2 plat_mtk_system_reset(void) 1403d91c9c3Skenny liang { 1413d91c9c3Skenny liang struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); 1423d91c9c3Skenny liang 1433d91c9c3Skenny liang INFO("MTK System Reset\n"); 1443d91c9c3Skenny liang 1453d91c9c3Skenny liang mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity); 1463d91c9c3Skenny liang 1473d91c9c3Skenny liang wfi(); 1483d91c9c3Skenny liang ERROR("MTK System Reset: operation not handled.\n"); 1493d91c9c3Skenny liang panic(); 1503d91c9c3Skenny liang } 1513d91c9c3Skenny liang 152*3c25ba44Skenny liang static void plat_mtk_power_domain_suspend(const psci_power_state_t *state) 153*3c25ba44Skenny liang { 154*3c25ba44Skenny liang uint64_t mpidr = read_mpidr(); 155*3c25ba44Skenny liang int cpu = MPIDR_AFFLVL0_VAL(mpidr); 156*3c25ba44Skenny liang int cluster = MPIDR_AFFLVL1_VAL(mpidr); 157*3c25ba44Skenny liang 158*3c25ba44Skenny liang spm_system_suspend(); 159*3c25ba44Skenny liang 160*3c25ba44Skenny liang /* init cpu reset arch as AARCH64 */ 161*3c25ba44Skenny liang mcucfg_init_archstate(cluster, cpu, 1); 162*3c25ba44Skenny liang mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 163*3c25ba44Skenny liang spm_set_bootaddr(secure_entrypoint); 164*3c25ba44Skenny liang 165*3c25ba44Skenny liang /* Prevent interrupts from spuriously waking up this cpu */ 166*3c25ba44Skenny liang mt_gic_cpuif_disable(); 167*3c25ba44Skenny liang mt_gic_irq_save(); 168*3c25ba44Skenny liang 169*3c25ba44Skenny liang if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) { 170*3c25ba44Skenny liang plat_mtk_cci_disable(); 171*3c25ba44Skenny liang disable_scu(mpidr); 172*3c25ba44Skenny liang } 173*3c25ba44Skenny liang } 174*3c25ba44Skenny liang 175*3c25ba44Skenny liang static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state) 176*3c25ba44Skenny liang { 177*3c25ba44Skenny liang uint64_t mpidr = read_mpidr(); 178*3c25ba44Skenny liang 179*3c25ba44Skenny liang mt_gic_init(); 180*3c25ba44Skenny liang mt_gic_irq_restore(); 181*3c25ba44Skenny liang 182*3c25ba44Skenny liang if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) { 183*3c25ba44Skenny liang enable_scu(mpidr); 184*3c25ba44Skenny liang plat_mtk_cci_enable(); 185*3c25ba44Skenny liang plat_dcm_restore_cluster_on(mpidr); 186*3c25ba44Skenny liang } 187*3c25ba44Skenny liang 188*3c25ba44Skenny liang mmio_write_32(EMI_WFIFO, 0xf); 189*3c25ba44Skenny liang spm_system_suspend_finish(); 190*3c25ba44Skenny liang } 191*3c25ba44Skenny liang 192*3c25ba44Skenny liang static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state) 193*3c25ba44Skenny liang { 194*3c25ba44Skenny liang assert(PLAT_MAX_PWR_LVL >= 2); 195*3c25ba44Skenny liang 196*3c25ba44Skenny liang for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 197*3c25ba44Skenny liang req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; 198*3c25ba44Skenny liang } 199*3c25ba44Skenny liang 200e977b4dbSkenny liang /******************************************************************************* 2013fa9dec4Skenny liang * MTK_platform handler called when an affinity instance is about to be turned 2023fa9dec4Skenny liang * on. The level and mpidr determine the affinity instance. 2033fa9dec4Skenny liang ******************************************************************************/ 2043fa9dec4Skenny liang static const plat_psci_ops_t plat_plat_pm_ops = { 2053fa9dec4Skenny liang .cpu_standby = NULL, 2067352f329Skenny liang .pwr_domain_on = plat_mtk_power_domain_on, 2077352f329Skenny liang .pwr_domain_on_finish = plat_mtk_power_domain_on_finish, 2087352f329Skenny liang .pwr_domain_off = plat_mtk_power_domain_off, 209*3c25ba44Skenny liang .pwr_domain_suspend = plat_mtk_power_domain_suspend, 210*3c25ba44Skenny liang .pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish, 211e977b4dbSkenny liang .system_off = plat_mtk_system_off, 2123d91c9c3Skenny liang .system_reset = plat_mtk_system_reset, 2133fa9dec4Skenny liang .validate_power_state = NULL, 214*3c25ba44Skenny liang .get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state, 2153fa9dec4Skenny liang }; 2163fa9dec4Skenny liang 2173fa9dec4Skenny liang int plat_setup_psci_ops(uintptr_t sec_entrypoint, 2183fa9dec4Skenny liang const plat_psci_ops_t **psci_ops) 2193fa9dec4Skenny liang { 2203fa9dec4Skenny liang *psci_ops = &plat_plat_pm_ops; 2213fa9dec4Skenny liang secure_entrypoint = sec_entrypoint; 2223fa9dec4Skenny liang return 0; 2233fa9dec4Skenny liang } 224