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