1 /*
2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <platform_def.h>
10 
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <lib/mmio.h>
14 #include <plat/common/platform.h>
15 
16 #include <hi3660.h>
17 #include <hisi_ipc.h>
18 #include "../../hikey960_private.h"
19 
20 #define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
21 #define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
22 #define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
23 #define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
24 #define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
25 #define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
26 #define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
27 #define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
28 #define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
29 					 ((d) * 4))
30 #define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
31 #define IPC_LOCK_REG			(IPC_BASE + 0xA00)
32 #define IPC_ACK_BIT_SHIFT		(1 << 7)
33 #define IPC_UNLOCK_VALUE		(0x1ACCE551)
34 
35 /*********************************************************
36  *bit[31:24]:0~AP
37  *bit[23:16]:0x1~A15, 0x2~A7
38  *bit[15:8]:0~ON, 1~OFF
39  *bit[7:0]:0x3 cpu power mode
40  *********************************************************/
41 #define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
42 	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
43 
44 /*********************************************************
45  *bit[15:8]:0~no idle, 1~idle
46  *bit[7:0]:cpux
47  *********************************************************/
48 
49 #define IPC_CMD_PARA(is_idle, cpu) \
50 	((is_idle << 8) | (cpu))
51 
52 #define IPC_STATE_IDLE			0x10
53 
54 enum src_id {
55 	SRC_IDLE = 0,
56 	SRC_A15 = 1 << 0,
57 	SRC_A7 = 1 << 1,
58 	SRC_IOM3 = 1 << 2,
59 	SRC_LPM3 = 1 << 3
60 };
61 
62 /*lpm3's mailboxs are 13~17*/
63 enum lpm3_mbox_id {
64 	LPM3_MBX0 = 13,
65 	LPM3_MBX1,
66 	LPM3_MBX2,
67 	LPM3_MBX3,
68 	LPM3_MBX4,
69 };
70 
cpu_relax(void)71 static void cpu_relax(void)
72 {
73 	volatile int i;
74 
75 	for (i = 0; i < 10; i++)
76 		nop();
77 }
78 
79 static inline void
hisi_ipc_clear_ack(enum src_id source,enum lpm3_mbox_id mbox)80 hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
81 {
82 	unsigned int int_status = 0;
83 
84 	do {
85 		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
86 		int_status &= 0xF0;
87 		cpu_relax();
88 	} while (int_status != IPC_ACK_BIT_SHIFT);
89 
90 	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
91 }
92 
93 static void
hisi_ipc_send_cmd_with_ack(enum src_id source,enum lpm3_mbox_id mbox,unsigned int cmdtype,unsigned int cmdpara)94 hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
95 			   unsigned int cmdtype, unsigned int cmdpara)
96 {
97 	unsigned int regval;
98 	unsigned int mask;
99 	unsigned int state;
100 
101 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
102 	/* wait for idle and occupy */
103 	do {
104 		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
105 		if (state == IPC_STATE_IDLE) {
106 			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
107 			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
108 			if (regval == source)
109 				break;
110 		}
111 		cpu_relax();
112 
113 	} while (1);
114 
115 	/* auto answer */
116 	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
117 
118 	mask = (~((int)source | SRC_LPM3) & 0x3F);
119 	/* mask the other cpus */
120 	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
121 	/* set data */
122 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
123 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
124 	/* send cmd */
125 	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
126 	/* wait ack and clear */
127 	hisi_ipc_clear_ack(source, mbox);
128 
129 	/* release mailbox */
130 	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
131 }
132 
hisi_ipc_pm_on_off(unsigned int core,unsigned int cluster,enum pm_mode mode)133 void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
134 			enum pm_mode mode)
135 {
136 	unsigned int cmdtype = 0;
137 	unsigned int cmdpara = 0;
138 	enum src_id source = SRC_IDLE;
139 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
140 
141 	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
142 	cmdpara = IPC_CMD_PARA(0, core);
143 	source = cluster ? SRC_A7 : SRC_A15;
144 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
145 }
146 
hisi_ipc_pm_suspend(unsigned int core,unsigned int cluster,unsigned int affinity_level)147 void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
148 			 unsigned int affinity_level)
149 {
150 	unsigned int cmdtype = 0;
151 	unsigned int cmdpara = 0;
152 	enum src_id source = SRC_IDLE;
153 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
154 
155 	if (affinity_level == 0x3)
156 		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
157 	else
158 		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
159 
160 	cmdpara = IPC_CMD_PARA(1, core);
161 	source = cluster ? SRC_A7 : SRC_A15;
162 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
163 }
164 
hisi_ipc_psci_system_off(unsigned int core,unsigned int cluster)165 void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
166 {
167 	unsigned int cmdtype = 0;
168 	unsigned int cmdpara = 0;
169 	enum src_id source = SRC_IDLE;
170 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
171 
172 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
173 	cmdpara = IPC_CMD_PARA(0, 0);
174 	source = cluster ? SRC_A7 : SRC_A15;
175 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
176 }
177 
hisi_ipc_psci_system_reset(unsigned int core,unsigned int cluster,unsigned int cmd_id)178 void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
179 				unsigned int cmd_id)
180 {
181 	unsigned int cmdtype = 0;
182 	unsigned int cmdpara = 0;
183 	enum src_id source = SRC_IDLE;
184 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
185 
186 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
187 	cmdpara = cmd_id;
188 	source = cluster ? SRC_A7 : SRC_A15;
189 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
190 }
191 
hisi_ipc_init(void)192 int hisi_ipc_init(void)
193 {
194 	int ret = 0;
195 	enum lpm3_mbox_id  i = LPM3_MBX0;
196 
197 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
198 	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
199 		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
200 		mmio_write_32(IPC_MBX_IMASK_REG(i),
201 			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
202 		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
203 	}
204 
205 	return ret;
206 }
207