blob: 70ccfa5accc4ec1080ce808e4384bbadb54498cf [file] [log] [blame]
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +03001/*
2 * Copyright (C) 2018 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +03008#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <common/debug.h>
11#include <lib/mmio.h>
12
13#include <plat_marvell.h>
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030014#include <mss_ipc_drv.h>
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030015
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
21unsigned long mv_pm_ipc_msg_base;
22unsigned int mv_pm_ipc_queue_size;
23
24unsigned int msg_sync;
25int msg_index = IPC_CH_MSG_IDX;
26
27/******************************************************************************
28 * mss_pm_ipc_init
29 *
30 * DESCRIPTION: Initialize PM IPC infrastructure
31 ******************************************************************************
32 */
33int 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 */
52unsigned 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 */
75int 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 */
90int 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}