1 /*
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
mcdi_mbox_read(uint32_t id)13 static inline uint32_t mcdi_mbox_read(uint32_t id)
14 {
15 return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
16 }
17
mcdi_mbox_write(uint32_t id,uint32_t val)18 static 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
sspm_set_bootaddr(uint32_t bootaddr)23 void sspm_set_bootaddr(uint32_t bootaddr)
24 {
25 mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr);
26 }
27
sspm_cluster_pwr_off_notify(uint32_t cluster)28 void sspm_cluster_pwr_off_notify(uint32_t cluster)
29 {
30 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1);
31 }
32
sspm_cluster_pwr_on_notify(uint32_t cluster)33 void sspm_cluster_pwr_on_notify(uint32_t cluster)
34 {
35 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0);
36 }
37
sspm_standbywfi_irq_enable(uint32_t cpu_idx)38 void sspm_standbywfi_irq_enable(uint32_t cpu_idx)
39 {
40 mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx));
41 }
42
mcdi_avail_cpu_mask_read(void)43 uint32_t mcdi_avail_cpu_mask_read(void)
44 {
45 return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
46 }
47
mcdi_avail_cpu_mask_write(uint32_t mask)48 uint32_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
mcdi_avail_cpu_mask_set(uint32_t mask)55 uint32_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
mcdi_avail_cpu_mask_clr(uint32_t mask)66 uint32_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
mcdi_cpu_cluster_pwr_stat_read(void)77 uint32_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
target_mask(int cluster,int cpu_idx,bool on)88 static 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
mcdi_pause_clr(int cluster,int cpu_idx,bool on)109 void 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
mcdi_pause_set(int cluster,int cpu_idx,bool on)118 void 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
mcdi_pause(void)137 void 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
mcdi_unpause(void)148 void 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
mcdi_hotplug_wait_ack(int cluster,int cpu_idx,bool on)155 void 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
mcdi_hotplug_clr(int cluster,int cpu_idx,bool on)165 void 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
mcdi_hotplug_set(int cluster,int cpu_idx,bool on)183 void 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
check_mcdi_ctl_stat(void)201 bool 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
mcdi_init(void)256 void mcdi_init(void)
257 {
258 mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */
259 }
260