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/mmio.h>
12 
13 #include <plat_marvell.h>
14 #include <mss_ipc_drv.h>
15 
16 #define IPC_MSG_BASE_MASK		MVEBU_REGS_BASE_MASK
17 
18 #define IPC_CH_NUM_OF_MSG		(16)
19 #define IPC_CH_MSG_IDX			(-1)
20 
21 unsigned long mv_pm_ipc_msg_base;
22 unsigned int  mv_pm_ipc_queue_size;
23 
24 unsigned int msg_sync;
25 int msg_index = IPC_CH_MSG_IDX;
26 
27 /******************************************************************************
28  * mss_pm_ipc_init
29  *
30  * DESCRIPTION: Initialize PM IPC infrastructure
31  ******************************************************************************
32  */
mv_pm_ipc_init(unsigned long ipc_control_addr)33 int mv_pm_ipc_init(unsigned long ipc_control_addr)
34 {
35 	struct mss_pm_ipc_ctrl *ipc_control =
36 			(struct mss_pm_ipc_ctrl *)ipc_control_addr;
37 
38 	/* Initialize PM IPC control block */
39 	mv_pm_ipc_msg_base     = ipc_control->msg_base_address |
40 				 IPC_MSG_BASE_MASK;
41 	mv_pm_ipc_queue_size   = ipc_control->queue_size;
42 
43 	return 0;
44 }
45 
46 /******************************************************************************
47  * mv_pm_ipc_queue_addr_get
48  *
49  * DESCRIPTION: Returns the IPC queue address
50  ******************************************************************************
51  */
mv_pm_ipc_queue_addr_get(void)52 unsigned int mv_pm_ipc_queue_addr_get(void)
53 {
54 	unsigned int addr;
55 
56 	inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
57 	msg_index = msg_index + 1;
58 	if (msg_index >= IPC_CH_NUM_OF_MSG)
59 		msg_index = 0;
60 
61 	addr = (unsigned int)(mv_pm_ipc_msg_base +
62 	       (msg_index * mv_pm_ipc_queue_size));
63 
64 	flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
65 
66 	return addr;
67 }
68 
69 /******************************************************************************
70  * mv_pm_ipc_msg_rx
71  *
72  * DESCRIPTION: Retrieve message from IPC channel
73  ******************************************************************************
74  */
mv_pm_ipc_msg_rx(unsigned int channel_id,struct mss_pm_ipc_msg * msg)75 int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg)
76 {
77 	unsigned int addr = mv_pm_ipc_queue_addr_get();
78 
79 	msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC);
80 
81 	return 0;
82 }
83 
84 /******************************************************************************
85  * mv_pm_ipc_msg_tx
86  *
87  * DESCRIPTION: Send message via IPC channel
88  ******************************************************************************
89  */
mv_pm_ipc_msg_tx(unsigned int channel_id,unsigned int msg_id,unsigned int cluster_power_state)90 int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
91 					unsigned int cluster_power_state)
92 {
93 	unsigned int addr = mv_pm_ipc_queue_addr_get();
94 
95 	/* Validate the entry for message placed by the host is free */
96 	if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) {
97 		inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
98 		msg_sync = msg_sync + 1;
99 		flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
100 
101 		mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync);
102 		mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id);
103 		mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id);
104 		mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC,
105 			      cluster_power_state);
106 		mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY);
107 
108 	} else {
109 		ERROR("%s: FAILED\n", __func__);
110 	}
111 
112 	return 0;
113 }
114