1 /*
2  * Copyright (C) 2018 Marvell International Ltd.
3  *
4  * SPDX-License-Identifier:     BSD-3-Clause
5  * https://spdx.org/licenses
6  */
7 
8 #include <string.h>
9 
10 #include <common/debug.h>
11 #include <lib/psci/psci.h>
12 #include <lib/mmio.h>
13 
14 #include <mss_pm_ipc.h>
15 
16 /*
17  * SISR is 32 bit interrupt register representing 32 interrupts
18  *
19  * +======+=============+=============+
20  * + Bits + 31          + 30 - 00     +
21  * +======+=============+=============+
22  * + Desc + MSS Msg Int + Reserved    +
23  * +======+=============+=============+
24  */
25 #define MSS_SISR		(MVEBU_REGS_BASE + 0x5800D0)
26 #define MSS_SISTR		(MVEBU_REGS_BASE + 0x5800D8)
27 
28 #define MSS_MSG_INT_MASK	(0x80000000)
29 #define MSS_TIMER_BASE		(MVEBU_REGS_BASE_MASK + 0x580110)
30 #define MSS_TRIGGER_TIMEOUT	(2000)
31 
32 /*****************************************************************************
33  * mss_pm_ipc_msg_send
34  *
35  * DESCRIPTION: create and transmit IPC message
36  *****************************************************************************
37  */
mss_pm_ipc_msg_send(unsigned int channel_id,unsigned int msg_id,const psci_power_state_t * target_state)38 int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
39 			const psci_power_state_t *target_state)
40 {
41 	/* Transmit IPC message */
42 #ifndef DISABLE_CLUSTER_LEVEL
43 	mv_pm_ipc_msg_tx(channel_id, msg_id,
44 			 (unsigned int)target_state->pwr_domain_state[
45 					MPIDR_AFFLVL1]);
46 #else
47 	mv_pm_ipc_msg_tx(channel_id, msg_id, 0);
48 #endif
49 
50 	return 0;
51 }
52 
53 /*****************************************************************************
54  * mss_pm_ipc_msg_trigger
55  *
56  * DESCRIPTION: Trigger IPC message interrupt to MSS
57  *****************************************************************************
58  */
mss_pm_ipc_msg_trigger(void)59 int mss_pm_ipc_msg_trigger(void)
60 {
61 	unsigned int timeout;
62 	unsigned int t_end;
63 	unsigned int t_start = mmio_read_32(MSS_TIMER_BASE);
64 
65 	mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK);
66 
67 	do {
68 		/* wait while SCP process incoming interrupt */
69 		if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK)
70 			break;
71 
72 		/* check timeout */
73 		t_end = mmio_read_32(MSS_TIMER_BASE);
74 
75 		timeout = ((t_start > t_end) ?
76 			   (t_start - t_end) : (t_end - t_start));
77 		if (timeout > MSS_TRIGGER_TIMEOUT) {
78 			ERROR("PM MSG Trigger Timeout\n");
79 			break;
80 		}
81 
82 	} while (1);
83 
84 	return 0;
85 }
86