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