1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stdarg.h> 8*91f16700Schasinglulu #include <stdio.h> 9*91f16700Schasinglulu #include <string.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <platform_def.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <arch_helpers.h> 14*91f16700Schasinglulu #include <common/debug.h> 15*91f16700Schasinglulu #include <lib/mmio.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu #include <hisi_ipc.h> 18*91f16700Schasinglulu #include <hisi_sram_map.h> 19*91f16700Schasinglulu 20*91f16700Schasinglulu static int ipc_init; 21*91f16700Schasinglulu 22*91f16700Schasinglulu static unsigned int cpu_ipc_num[PLATFORM_CLUSTER_COUNT][PLATFORM_CORE_COUNT_PER_CLUSTER] = { 23*91f16700Schasinglulu { 24*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU0_PD, 25*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU1_PD, 26*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU2_PD, 27*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU3_PD, 28*91f16700Schasinglulu }, 29*91f16700Schasinglulu { 30*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU4_PD, 31*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU5_PD, 32*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU6_PD, 33*91f16700Schasinglulu HISI_IPC_MCU_INT_SRC_ACPU7_PD, 34*91f16700Schasinglulu } 35*91f16700Schasinglulu }; 36*91f16700Schasinglulu 37*91f16700Schasinglulu int hisi_cpus_pd_in_cluster_besides_curr(unsigned int cpu, 38*91f16700Schasinglulu unsigned int cluster) 39*91f16700Schasinglulu { 40*91f16700Schasinglulu unsigned int val = 0, cpu_val = 0; 41*91f16700Schasinglulu int i; 42*91f16700Schasinglulu 43*91f16700Schasinglulu val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 44*91f16700Schasinglulu val = val >> (cluster * 16); 45*91f16700Schasinglulu 46*91f16700Schasinglulu for (i = 0; i < PLATFORM_CORE_COUNT_PER_CLUSTER; i++) { 47*91f16700Schasinglulu 48*91f16700Schasinglulu if (cpu == i) 49*91f16700Schasinglulu continue; 50*91f16700Schasinglulu 51*91f16700Schasinglulu cpu_val = (val >> (i * 4)) & 0xF; 52*91f16700Schasinglulu if (cpu_val == 0x8) 53*91f16700Schasinglulu return 0; 54*91f16700Schasinglulu } 55*91f16700Schasinglulu 56*91f16700Schasinglulu return 1; 57*91f16700Schasinglulu } 58*91f16700Schasinglulu 59*91f16700Schasinglulu int hisi_cpus_powered_off_besides_curr(unsigned int cpu) 60*91f16700Schasinglulu { 61*91f16700Schasinglulu unsigned int val; 62*91f16700Schasinglulu 63*91f16700Schasinglulu val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 64*91f16700Schasinglulu return (val == (0x8 << (cpu * 4))); 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu static void hisi_ipc_send(unsigned int ipc_num) 68*91f16700Schasinglulu { 69*91f16700Schasinglulu if (!ipc_init) { 70*91f16700Schasinglulu printf("error ipc base is null!!!\n"); 71*91f16700Schasinglulu return; 72*91f16700Schasinglulu } 73*91f16700Schasinglulu 74*91f16700Schasinglulu mmio_write_32(HISI_IPC_CPU_RAW_INT_ADDR, 1 << ipc_num); 75*91f16700Schasinglulu } 76*91f16700Schasinglulu 77*91f16700Schasinglulu void hisi_ipc_spin_lock(unsigned int signal) 78*91f16700Schasinglulu { 79*91f16700Schasinglulu unsigned int hs_ctrl; 80*91f16700Schasinglulu 81*91f16700Schasinglulu if (signal >= HISI_IPC_INT_SRC_NUM) 82*91f16700Schasinglulu return; 83*91f16700Schasinglulu 84*91f16700Schasinglulu do { 85*91f16700Schasinglulu hs_ctrl = mmio_read_32(HISI_IPC_ACPU_CTRL(signal)); 86*91f16700Schasinglulu } while (hs_ctrl); 87*91f16700Schasinglulu } 88*91f16700Schasinglulu 89*91f16700Schasinglulu void hisi_ipc_spin_unlock(unsigned int signal) 90*91f16700Schasinglulu { 91*91f16700Schasinglulu if (signal >= HISI_IPC_INT_SRC_NUM) 92*91f16700Schasinglulu return; 93*91f16700Schasinglulu 94*91f16700Schasinglulu mmio_write_32(HISI_IPC_ACPU_CTRL(signal), 0); 95*91f16700Schasinglulu } 96*91f16700Schasinglulu 97*91f16700Schasinglulu void hisi_ipc_cpu_on_off(unsigned int cpu, unsigned int cluster, 98*91f16700Schasinglulu unsigned int mode) 99*91f16700Schasinglulu { 100*91f16700Schasinglulu unsigned int val = 0; 101*91f16700Schasinglulu unsigned int offset; 102*91f16700Schasinglulu 103*91f16700Schasinglulu if (mode == HISI_IPC_PM_ON) 104*91f16700Schasinglulu offset = cluster * 16 + cpu * 4; 105*91f16700Schasinglulu else 106*91f16700Schasinglulu offset = cluster * 16 + cpu * 4 + 1; 107*91f16700Schasinglulu 108*91f16700Schasinglulu hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 109*91f16700Schasinglulu val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 110*91f16700Schasinglulu val |= (0x01 << offset); 111*91f16700Schasinglulu mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 112*91f16700Schasinglulu isb(); 113*91f16700Schasinglulu dsb(); 114*91f16700Schasinglulu hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 115*91f16700Schasinglulu 116*91f16700Schasinglulu hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 117*91f16700Schasinglulu } 118*91f16700Schasinglulu 119*91f16700Schasinglulu void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster) 120*91f16700Schasinglulu { 121*91f16700Schasinglulu hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_ON); 122*91f16700Schasinglulu } 123*91f16700Schasinglulu 124*91f16700Schasinglulu void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster) 125*91f16700Schasinglulu { 126*91f16700Schasinglulu hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_OFF); 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu void hisi_ipc_cluster_on_off(unsigned int cpu, unsigned int cluster, 130*91f16700Schasinglulu unsigned int mode) 131*91f16700Schasinglulu { 132*91f16700Schasinglulu unsigned int val = 0; 133*91f16700Schasinglulu unsigned int offset; 134*91f16700Schasinglulu 135*91f16700Schasinglulu if (mode == HISI_IPC_PM_ON) 136*91f16700Schasinglulu offset = cluster * 4; 137*91f16700Schasinglulu else 138*91f16700Schasinglulu offset = cluster * 4 + 1; 139*91f16700Schasinglulu 140*91f16700Schasinglulu hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 141*91f16700Schasinglulu val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 142*91f16700Schasinglulu val |= (0x01 << offset); 143*91f16700Schasinglulu mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 144*91f16700Schasinglulu isb(); 145*91f16700Schasinglulu dsb(); 146*91f16700Schasinglulu hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 147*91f16700Schasinglulu 148*91f16700Schasinglulu hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 149*91f16700Schasinglulu } 150*91f16700Schasinglulu 151*91f16700Schasinglulu void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster) 152*91f16700Schasinglulu { 153*91f16700Schasinglulu hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_ON); 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster) 157*91f16700Schasinglulu { 158*91f16700Schasinglulu hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_OFF); 159*91f16700Schasinglulu } 160*91f16700Schasinglulu 161*91f16700Schasinglulu void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster) 162*91f16700Schasinglulu { 163*91f16700Schasinglulu unsigned int val = 0; 164*91f16700Schasinglulu unsigned int offset; 165*91f16700Schasinglulu 166*91f16700Schasinglulu offset = cluster * 16 + cpu * 4 + 2; 167*91f16700Schasinglulu 168*91f16700Schasinglulu hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 169*91f16700Schasinglulu val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); 170*91f16700Schasinglulu val |= (0x01 << offset); 171*91f16700Schasinglulu mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); 172*91f16700Schasinglulu hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 173*91f16700Schasinglulu 174*91f16700Schasinglulu hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 175*91f16700Schasinglulu } 176*91f16700Schasinglulu 177*91f16700Schasinglulu void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster) 178*91f16700Schasinglulu { 179*91f16700Schasinglulu unsigned int val; 180*91f16700Schasinglulu unsigned int offset; 181*91f16700Schasinglulu 182*91f16700Schasinglulu offset = cluster * 4 + 1; 183*91f16700Schasinglulu 184*91f16700Schasinglulu hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 185*91f16700Schasinglulu if (hisi_cpus_pd_in_cluster_besides_curr(cpu, cluster)) { 186*91f16700Schasinglulu val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); 187*91f16700Schasinglulu val |= (0x01 << offset); 188*91f16700Schasinglulu mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); 189*91f16700Schasinglulu } 190*91f16700Schasinglulu hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 191*91f16700Schasinglulu 192*91f16700Schasinglulu hisi_ipc_send(cpu_ipc_num[cluster][cpu]); 193*91f16700Schasinglulu } 194*91f16700Schasinglulu 195*91f16700Schasinglulu void hisi_ipc_psci_system_off(void) 196*91f16700Schasinglulu { 197*91f16700Schasinglulu hisi_ipc_send(HISI_IPC_MCU_INT_SRC_ACPU_PD); 198*91f16700Schasinglulu } 199*91f16700Schasinglulu 200*91f16700Schasinglulu int hisi_ipc_init(void) 201*91f16700Schasinglulu { 202*91f16700Schasinglulu ipc_init = 1; 203*91f16700Schasinglulu 204*91f16700Schasinglulu mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, 0x8); 205*91f16700Schasinglulu mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, 0x8); 206*91f16700Schasinglulu return 0; 207*91f16700Schasinglulu } 208