blob: 29eebcb98f91b5fbb2eca6846dc465ebc415bd0b [file] [log] [blame]
developer555ed552019-08-21 22:49:49 +08001/*
2 * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <common/debug.h>
8#include <drivers/delay_timer.h>
9#include <lib/mmio.h>
10#include <sspm_reg.h>
11#include <mtk_mcdi.h>
12
13static inline uint32_t mcdi_mbox_read(uint32_t id)
14{
15 return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
16}
17
18static inline void mcdi_mbox_write(uint32_t id, uint32_t val)
19{
20 mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val);
21}
22
23void sspm_set_bootaddr(uint32_t bootaddr)
24{
25 mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr);
26}
27
28void sspm_cluster_pwr_off_notify(uint32_t cluster)
29{
30 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1);
31}
32
33void sspm_cluster_pwr_on_notify(uint32_t cluster)
34{
35 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0);
36}
37
38void sspm_standbywfi_irq_enable(uint32_t cpu_idx)
39{
40 mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx));
41}
42
43uint32_t mcdi_avail_cpu_mask_read(void)
44{
45 return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
46}
47
48uint32_t mcdi_avail_cpu_mask_write(uint32_t mask)
49{
50 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, mask);
51
52 return mask;
53}
54
55uint32_t mcdi_avail_cpu_mask_set(uint32_t mask)
56{
57 uint32_t m;
58
59 m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
60 m |= mask;
61 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m);
62
63 return m;
64}
65
66uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask)
67{
68 uint32_t m;
69
70 m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
71 m &= ~mask;
72 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m);
73
74 return m;
75}
76
77uint32_t mcdi_cpu_cluster_pwr_stat_read(void)
78{
79 return mcdi_mbox_read(MCDI_MBOX_CPU_CLUSTER_PWR_STAT);
80}
81
82#define PAUSE_BIT 1
83#define CLUSTER_OFF_OFS 20
84#define CPU_OFF_OFS 24
85#define CLUSTER_ON_OFS 4
86#define CPU_ON_OFS 8
87
88static uint32_t target_mask(int cluster, int cpu_idx, bool on)
89{
90 uint32_t t = 0;
91
92 if (on) {
93 if (cluster >= 0)
94 t |= BIT(cluster + CLUSTER_ON_OFS);
95
96 if (cpu_idx >= 0)
97 t |= BIT(cpu_idx + CPU_ON_OFS);
98 } else {
99 if (cluster >= 0)
100 t |= BIT(cluster + CLUSTER_OFF_OFS);
101
102 if (cpu_idx >= 0)
103 t |= BIT(cpu_idx + CPU_OFF_OFS);
104 }
105
106 return t;
107}
108
109void mcdi_pause_clr(int cluster, int cpu_idx, bool on)
110{
111 uint32_t tgt = target_mask(cluster, cpu_idx, on);
112 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION);
113
114 m &= ~tgt;
115 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
116}
117
118void mcdi_pause_set(int cluster, int cpu_idx, bool on)
119{
120 uint32_t tgt = target_mask(cluster, cpu_idx, on);
121 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION);
122 uint32_t tgtn = target_mask(-1, cpu_idx, !on);
123
124 /* request on and off at the same time to ensure it can be paused */
125 m |= tgt | tgtn;
126 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
127
128 /* wait pause_ack */
129 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK))
130 ;
131
132 /* clear non-requested operation */
133 m &= ~tgtn;
134 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
135}
136
137void mcdi_pause(void)
138{
139 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT);
140
141 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
142
143 /* wait pause_ack */
144 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK))
145 ;
146}
147
148void mcdi_unpause(void)
149{
150 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT);
151
152 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
153}
154
155void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on)
156{
157 uint32_t tgt = target_mask(cluster, cpu_idx, on);
158 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
159
160 /* wait until ack */
161 while (!(ack & tgt))
162 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
163}
164
165void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on)
166{
167 uint32_t tgt = target_mask(cluster, cpu_idx, on);
168 uint32_t tgt_cpu = target_mask(-1, cpu_idx, on);
169 uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD);
170 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
171
172 if (!(cmd & tgt))
173 return;
174
175 /* wait until ack */
176 while (!(ack & tgt_cpu))
177 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
178
179 cmd &= ~tgt;
180 mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd);
181}
182
183void mcdi_hotplug_set(int cluster, int cpu_idx, bool on)
184{
185 uint32_t tgt = target_mask(cluster, cpu_idx, on);
186 uint32_t tgt_cpu = target_mask(-1, cpu_idx, on);
187 uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD);
188 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
189
190 if ((cmd & tgt) == tgt)
191 return;
192
193 /* wait until ack clear */
194 while (ack & tgt_cpu)
195 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
196
197 cmd |= tgt;
198 mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd);
199}
200
201bool check_mcdi_ctl_stat(void)
202{
203 uint32_t clk_regs[] = {0x100010ac, 0x100010c8};
204 uint32_t clk_mask[] = {0x00028000, 0x00000018};
205 uint32_t tgt = target_mask(0, 0, true);
206 uint32_t m;
207 int i;
208
209 /* check clk status */
210 for (i = 0; i < ARRAY_SIZE(clk_regs); i++) {
211 if (mmio_read_32(clk_regs[i]) & clk_mask[i]) {
212 WARN("mcdi: clk check fail.\n");
213 return false;
214 }
215 }
216
217 /* check mcdi cmd handling */
218 m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT);
219 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
220
221 i = 500;
222 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK) && --i > 0)
223 udelay(10);
224
225 m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT);
226 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
227
228 if (i == 0) {
229 WARN("mcdi: pause_action fail.\n");
230 return false;
231 }
232
233 /* check mcdi cmd handling */
234 if (mcdi_mbox_read(MCDI_MBOX_HP_CMD) ||
235 mcdi_mbox_read(MCDI_MBOX_HP_ACK)) {
236 WARN("mcdi: hp_cmd fail.\n");
237 return false;
238 }
239
240 mcdi_mbox_write(MCDI_MBOX_HP_CMD, tgt);
241
242 i = 500;
243 while ((mcdi_mbox_read(MCDI_MBOX_HP_ACK) & tgt) != tgt && --i > 0)
244 udelay(10);
245
246 mcdi_mbox_write(MCDI_MBOX_HP_CMD, 0);
247
248 if (i == 0) {
249 WARN("mcdi: hp_ack fail.\n");
250 return false;
251 }
252
253 return true;
254}
255
256void mcdi_init(void)
257{
258 mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */
259}