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