1*1da57e54SGarmin.Chang /* 2*1da57e54SGarmin.Chang * Copyright (c) 2021, MediaTek Inc. All rights reserved. 3*1da57e54SGarmin.Chang * 4*1da57e54SGarmin.Chang * SPDX-License-Identifier: BSD-3-Clause 5*1da57e54SGarmin.Chang */ 6*1da57e54SGarmin.Chang 7*1da57e54SGarmin.Chang #include <assert.h> 8*1da57e54SGarmin.Chang 9*1da57e54SGarmin.Chang #include <common/debug.h> 10*1da57e54SGarmin.Chang #include <drivers/delay_timer.h> 11*1da57e54SGarmin.Chang #include <lib/mmio.h> 12*1da57e54SGarmin.Chang 13*1da57e54SGarmin.Chang #include <mcucfg.h> 14*1da57e54SGarmin.Chang #include <mtspmc.h> 15*1da57e54SGarmin.Chang #include <mtspmc_private.h> 16*1da57e54SGarmin.Chang #include <plat/common/platform.h> 17*1da57e54SGarmin.Chang 18*1da57e54SGarmin.Chang void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu) 19*1da57e54SGarmin.Chang { 20*1da57e54SGarmin.Chang mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu)); 21*1da57e54SGarmin.Chang } 22*1da57e54SGarmin.Chang 23*1da57e54SGarmin.Chang void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu) 24*1da57e54SGarmin.Chang { 25*1da57e54SGarmin.Chang mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu)); 26*1da57e54SGarmin.Chang /* Clear cpu's cpc sw hint */ 27*1da57e54SGarmin.Chang mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu)); 28*1da57e54SGarmin.Chang } 29*1da57e54SGarmin.Chang 30*1da57e54SGarmin.Chang void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr) 31*1da57e54SGarmin.Chang { 32*1da57e54SGarmin.Chang assert(cluster == 0U); 33*1da57e54SGarmin.Chang 34*1da57e54SGarmin.Chang mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr); 35*1da57e54SGarmin.Chang } 36*1da57e54SGarmin.Chang 37*1da57e54SGarmin.Chang uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu) 38*1da57e54SGarmin.Chang { 39*1da57e54SGarmin.Chang assert(cluster == 0U); 40*1da57e54SGarmin.Chang 41*1da57e54SGarmin.Chang return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR)); 42*1da57e54SGarmin.Chang } 43*1da57e54SGarmin.Chang 44*1da57e54SGarmin.Chang void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64) 45*1da57e54SGarmin.Chang { 46*1da57e54SGarmin.Chang uint32_t reg; 47*1da57e54SGarmin.Chang 48*1da57e54SGarmin.Chang assert(cluster == 0U); 49*1da57e54SGarmin.Chang 50*1da57e54SGarmin.Chang reg = per_cluster(cluster, MCUCFG_INITARCH); 51*1da57e54SGarmin.Chang 52*1da57e54SGarmin.Chang if (arm64) { 53*1da57e54SGarmin.Chang mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu)); 54*1da57e54SGarmin.Chang } else { 55*1da57e54SGarmin.Chang mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu)); 56*1da57e54SGarmin.Chang } 57*1da57e54SGarmin.Chang } 58*1da57e54SGarmin.Chang 59*1da57e54SGarmin.Chang /* 60*1da57e54SGarmin.Chang * Return subsystem's power state. 61*1da57e54SGarmin.Chang * 62*1da57e54SGarmin.Chang * @mask: mask to SPM_CPU_PWR_STATUS to query the power state 63*1da57e54SGarmin.Chang * of one subsystem. 64*1da57e54SGarmin.Chang * RETURNS: 65*1da57e54SGarmin.Chang * 0 (the subsys was powered off) 66*1da57e54SGarmin.Chang * 1 (the subsys was powered on) 67*1da57e54SGarmin.Chang */ 68*1da57e54SGarmin.Chang bool spm_get_powerstate(uint32_t mask) 69*1da57e54SGarmin.Chang { 70*1da57e54SGarmin.Chang return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask); 71*1da57e54SGarmin.Chang } 72*1da57e54SGarmin.Chang 73*1da57e54SGarmin.Chang bool spm_get_cluster_powerstate(unsigned int cluster) 74*1da57e54SGarmin.Chang { 75*1da57e54SGarmin.Chang assert(cluster == 0U); 76*1da57e54SGarmin.Chang 77*1da57e54SGarmin.Chang return spm_get_powerstate(MP0_CPUTOP); 78*1da57e54SGarmin.Chang } 79*1da57e54SGarmin.Chang 80*1da57e54SGarmin.Chang bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu) 81*1da57e54SGarmin.Chang { 82*1da57e54SGarmin.Chang uint32_t mask = BIT(cpu); 83*1da57e54SGarmin.Chang 84*1da57e54SGarmin.Chang assert(cluster == 0U); 85*1da57e54SGarmin.Chang 86*1da57e54SGarmin.Chang return spm_get_powerstate(mask); 87*1da57e54SGarmin.Chang } 88*1da57e54SGarmin.Chang 89*1da57e54SGarmin.Chang int spmc_init(void) 90*1da57e54SGarmin.Chang { 91*1da57e54SGarmin.Chang unsigned int cpu = plat_my_core_pos(); 92*1da57e54SGarmin.Chang 93*1da57e54SGarmin.Chang 94*1da57e54SGarmin.Chang INFO("SPM: enable CPC mode\n"); 95*1da57e54SGarmin.Chang 96*1da57e54SGarmin.Chang mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN); 97*1da57e54SGarmin.Chang 98*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B); 99*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B); 100*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B); 101*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B); 102*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B); 103*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B); 104*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B); 105*1da57e54SGarmin.Chang 106*1da57e54SGarmin.Chang mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG); 107*1da57e54SGarmin.Chang mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG); 108*1da57e54SGarmin.Chang mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG); 109*1da57e54SGarmin.Chang 110*1da57e54SGarmin.Chang mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE); 111*1da57e54SGarmin.Chang 112*1da57e54SGarmin.Chang /* Clear bootup cpu's cpc sw hint */ 113*1da57e54SGarmin.Chang mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu)); 114*1da57e54SGarmin.Chang 115*1da57e54SGarmin.Chang return 0; 116*1da57e54SGarmin.Chang } 117*1da57e54SGarmin.Chang 118*1da57e54SGarmin.Chang /* 119*1da57e54SGarmin.Chang * Power on a core with specified cluster and core index 120*1da57e54SGarmin.Chang * 121*1da57e54SGarmin.Chang * @cluster: the cluster ID of the CPU which to be powered on 122*1da57e54SGarmin.Chang * @cpu: the CPU ID of the CPU which to be powered on 123*1da57e54SGarmin.Chang */ 124*1da57e54SGarmin.Chang void spm_poweron_cpu(unsigned int cluster, unsigned int cpu) 125*1da57e54SGarmin.Chang { 126*1da57e54SGarmin.Chang /* info CPC that CPU hotplug on */ 127*1da57e54SGarmin.Chang mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN); 128*1da57e54SGarmin.Chang 129*1da57e54SGarmin.Chang /* Set mp0_spmc_pwr_on_cpuX = 1 */ 130*1da57e54SGarmin.Chang mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON); 131*1da57e54SGarmin.Chang 132*1da57e54SGarmin.Chang /* wait for power on ack */ 133*1da57e54SGarmin.Chang while (!spm_get_cpu_powerstate(cluster, cpu)) 134*1da57e54SGarmin.Chang ; 135*1da57e54SGarmin.Chang 136*1da57e54SGarmin.Chang /* info CPC that CPU hotplug off */ 137*1da57e54SGarmin.Chang mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN); 138*1da57e54SGarmin.Chang } 139*1da57e54SGarmin.Chang 140*1da57e54SGarmin.Chang /* 141*1da57e54SGarmin.Chang * Power off a core with specified cluster and core index 142*1da57e54SGarmin.Chang * 143*1da57e54SGarmin.Chang * @cluster: the cluster ID of the CPU which to be powered off 144*1da57e54SGarmin.Chang * @cpu: the CPU ID of the CPU which to be powered off 145*1da57e54SGarmin.Chang */ 146*1da57e54SGarmin.Chang void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu) 147*1da57e54SGarmin.Chang { 148*1da57e54SGarmin.Chang /* Set mp0_spmc_pwr_on_cpuX = 0 */ 149*1da57e54SGarmin.Chang mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON); 150*1da57e54SGarmin.Chang } 151*1da57e54SGarmin.Chang 152*1da57e54SGarmin.Chang /* 153*1da57e54SGarmin.Chang * Power off a cluster with specified index 154*1da57e54SGarmin.Chang * 155*1da57e54SGarmin.Chang * @cluster: the cluster index which to be powered off 156*1da57e54SGarmin.Chang */ 157*1da57e54SGarmin.Chang void spm_poweroff_cluster(unsigned int cluster) 158*1da57e54SGarmin.Chang { 159*1da57e54SGarmin.Chang /* No need to power on/off cluster on single cluster platform */ 160*1da57e54SGarmin.Chang assert(false); 161*1da57e54SGarmin.Chang } 162*1da57e54SGarmin.Chang 163*1da57e54SGarmin.Chang /* 164*1da57e54SGarmin.Chang * Power on a cluster with specified index 165*1da57e54SGarmin.Chang * 166*1da57e54SGarmin.Chang * @cluster: the cluster index which to be powered on 167*1da57e54SGarmin.Chang */ 168*1da57e54SGarmin.Chang void spm_poweron_cluster(unsigned int cluster) 169*1da57e54SGarmin.Chang { 170*1da57e54SGarmin.Chang /* No need to power on/off cluster on single cluster platform */ 171*1da57e54SGarmin.Chang assert(false); 172*1da57e54SGarmin.Chang } 173