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