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