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