xref: /rk3399_ARM-atf/plat/mediatek/mt8195/drivers/spmc/mtspmc.c (revision 0d82eff6fbf401a6d268a9efdb69d6e146ec510f)
1*0d82eff6SJames Liao /*
2*0d82eff6SJames Liao  * Copyright (c) 2020, MediaTek Inc. All rights reserved.
3*0d82eff6SJames Liao  *
4*0d82eff6SJames Liao  * SPDX-License-Identifier: BSD-3-Clause
5*0d82eff6SJames Liao  */
6*0d82eff6SJames Liao 
7*0d82eff6SJames Liao #include <assert.h>
8*0d82eff6SJames Liao 
9*0d82eff6SJames Liao #include <common/debug.h>
10*0d82eff6SJames Liao #include <drivers/delay_timer.h>
11*0d82eff6SJames Liao #include <lib/mmio.h>
12*0d82eff6SJames Liao 
13*0d82eff6SJames Liao #include <mcucfg.h>
14*0d82eff6SJames Liao #include <mtspmc.h>
15*0d82eff6SJames Liao #include <mtspmc_private.h>
16*0d82eff6SJames Liao 
17*0d82eff6SJames Liao 
18*0d82eff6SJames Liao void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu)
19*0d82eff6SJames Liao {
20*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
21*0d82eff6SJames Liao }
22*0d82eff6SJames Liao 
23*0d82eff6SJames Liao void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu)
24*0d82eff6SJames Liao {
25*0d82eff6SJames Liao 	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
26*0d82eff6SJames Liao }
27*0d82eff6SJames Liao 
28*0d82eff6SJames Liao void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr)
29*0d82eff6SJames Liao {
30*0d82eff6SJames Liao 	assert(cluster == 0U);
31*0d82eff6SJames Liao 
32*0d82eff6SJames Liao 	mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
33*0d82eff6SJames Liao }
34*0d82eff6SJames Liao 
35*0d82eff6SJames Liao uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu)
36*0d82eff6SJames Liao {
37*0d82eff6SJames Liao 	assert(cluster == 0U);
38*0d82eff6SJames Liao 
39*0d82eff6SJames Liao 	return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
40*0d82eff6SJames Liao }
41*0d82eff6SJames Liao 
42*0d82eff6SJames Liao void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64)
43*0d82eff6SJames Liao {
44*0d82eff6SJames Liao 	uint32_t reg;
45*0d82eff6SJames Liao 
46*0d82eff6SJames Liao 	assert(cluster == 0U);
47*0d82eff6SJames Liao 
48*0d82eff6SJames Liao 	reg = per_cluster(cluster, MCUCFG_INITARCH);
49*0d82eff6SJames Liao 
50*0d82eff6SJames Liao 	if (arm64) {
51*0d82eff6SJames Liao 		mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
52*0d82eff6SJames Liao 	} else {
53*0d82eff6SJames Liao 		mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
54*0d82eff6SJames Liao 	}
55*0d82eff6SJames Liao }
56*0d82eff6SJames Liao 
57*0d82eff6SJames Liao /**
58*0d82eff6SJames Liao  * Return subsystem's power state.
59*0d82eff6SJames Liao  *
60*0d82eff6SJames Liao  * @mask: mask to SPM_CPU_PWR_STATUS to query the power state
61*0d82eff6SJames Liao  *        of one subsystem.
62*0d82eff6SJames Liao  * RETURNS:
63*0d82eff6SJames Liao  * 0 (the subsys was powered off)
64*0d82eff6SJames Liao  * 1 (the subsys was powered on)
65*0d82eff6SJames Liao  */
66*0d82eff6SJames Liao bool spm_get_powerstate(uint32_t mask)
67*0d82eff6SJames Liao {
68*0d82eff6SJames Liao 	return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask) != 0U;
69*0d82eff6SJames Liao }
70*0d82eff6SJames Liao 
71*0d82eff6SJames Liao bool spm_get_cluster_powerstate(uint32_t cluster)
72*0d82eff6SJames Liao {
73*0d82eff6SJames Liao 	assert(cluster == 0U);
74*0d82eff6SJames Liao 
75*0d82eff6SJames Liao 	return spm_get_powerstate(MP0_CPUTOP);
76*0d82eff6SJames Liao }
77*0d82eff6SJames Liao 
78*0d82eff6SJames Liao bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu)
79*0d82eff6SJames Liao {
80*0d82eff6SJames Liao 	uint32_t mask = BIT(cpu);
81*0d82eff6SJames Liao 
82*0d82eff6SJames Liao 	assert(cluster == 0U);
83*0d82eff6SJames Liao 
84*0d82eff6SJames Liao 	return spm_get_powerstate(mask);
85*0d82eff6SJames Liao }
86*0d82eff6SJames Liao 
87*0d82eff6SJames Liao int spmc_init(void)
88*0d82eff6SJames Liao {
89*0d82eff6SJames Liao 	INFO("SPM: enable CPC mode\n");
90*0d82eff6SJames Liao 
91*0d82eff6SJames Liao 	mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
92*0d82eff6SJames Liao 
93*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
94*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
95*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
96*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
97*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
98*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
99*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
100*0d82eff6SJames Liao 
101*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(1));
102*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(2));
103*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(3));
104*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(4));
105*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(5));
106*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(6));
107*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(7));
108*0d82eff6SJames Liao 
109*0d82eff6SJames Liao 	mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
110*0d82eff6SJames Liao 	mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
111*0d82eff6SJames Liao 	mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
112*0d82eff6SJames Liao 
113*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
114*0d82eff6SJames Liao 
115*0d82eff6SJames Liao 	return 0;
116*0d82eff6SJames Liao }
117*0d82eff6SJames Liao 
118*0d82eff6SJames Liao /**
119*0d82eff6SJames Liao  * Power on a core with specified cluster and core index
120*0d82eff6SJames Liao  *
121*0d82eff6SJames Liao  * @cluster: the cluster ID of the CPU which to be powered on
122*0d82eff6SJames Liao  * @cpu: the CPU ID of the CPU which to be powered on
123*0d82eff6SJames Liao  */
124*0d82eff6SJames Liao void spm_poweron_cpu(uint32_t cluster, uint32_t cpu)
125*0d82eff6SJames Liao {
126*0d82eff6SJames Liao 	/* set to 0 after BIG VPROC bulk on & before B-core power on seq. */
127*0d82eff6SJames Liao 	if (cpu >= 4U) {
128*0d82eff6SJames Liao 		mmio_write_32(DREQ20_BIG_VPROC_ISO, 0U);
129*0d82eff6SJames Liao 	}
130*0d82eff6SJames Liao 
131*0d82eff6SJames Liao 	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
132*0d82eff6SJames Liao 	mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
133*0d82eff6SJames Liao 
134*0d82eff6SJames Liao 	while (!spm_get_cpu_powerstate(cluster, cpu)) {
135*0d82eff6SJames Liao 	}
136*0d82eff6SJames Liao 
137*0d82eff6SJames Liao 	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
138*0d82eff6SJames Liao 
139*0d82eff6SJames Liao 	/* Enable Big CPU Last PC */
140*0d82eff6SJames Liao 	if (cpu >= 4U) {
141*0d82eff6SJames Liao 		mmio_clrbits_32(LAST_PC_REG(cpu), BIT(3));
142*0d82eff6SJames Liao 	}
143*0d82eff6SJames Liao }
144*0d82eff6SJames Liao 
145*0d82eff6SJames Liao /**
146*0d82eff6SJames Liao  * Power off a core with specified cluster and core index
147*0d82eff6SJames Liao  *
148*0d82eff6SJames Liao  * @cluster: the cluster ID of the CPU which to be powered off
149*0d82eff6SJames Liao  * @cpu: the CPU ID of the CPU which to be powered off
150*0d82eff6SJames Liao  */
151*0d82eff6SJames Liao void spm_poweroff_cpu(uint32_t cluster, uint32_t cpu)
152*0d82eff6SJames Liao {
153*0d82eff6SJames Liao 	/* Set mp0_spmc_pwr_on_cpuX = 0 */
154*0d82eff6SJames Liao 	mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
155*0d82eff6SJames Liao }
156*0d82eff6SJames Liao 
157*0d82eff6SJames Liao /**
158*0d82eff6SJames Liao  * Power off a cluster with specified index
159*0d82eff6SJames Liao  *
160*0d82eff6SJames Liao  * @cluster: the cluster index which to be powered off
161*0d82eff6SJames Liao  */
162*0d82eff6SJames Liao void spm_poweroff_cluster(uint32_t cluster)
163*0d82eff6SJames Liao {
164*0d82eff6SJames Liao 	/* No need to power on/off cluster on single cluster platform */
165*0d82eff6SJames Liao 	assert(false);
166*0d82eff6SJames Liao }
167*0d82eff6SJames Liao 
168*0d82eff6SJames Liao /**
169*0d82eff6SJames Liao  * Power on a cluster with specified index
170*0d82eff6SJames Liao  *
171*0d82eff6SJames Liao  * @cluster: the cluster index which to be powered on
172*0d82eff6SJames Liao  */
173*0d82eff6SJames Liao void spm_poweron_cluster(uint32_t cluster)
174*0d82eff6SJames Liao {
175*0d82eff6SJames Liao 	/* No need to power on/off cluster on single cluster platform */
176*0d82eff6SJames Liao 	assert(false);
177*0d82eff6SJames Liao }
178