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