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