xref: /arm-trusted-firmware/plat/allwinner/common/sunxi_cpu_ops.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <platform_def.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <arch_helpers.h>
12*91f16700Schasinglulu #include <common/debug.h>
13*91f16700Schasinglulu #include <drivers/delay_timer.h>
14*91f16700Schasinglulu #include <lib/mmio.h>
15*91f16700Schasinglulu #include <lib/utils_def.h>
16*91f16700Schasinglulu #include <plat/common/platform.h>
17*91f16700Schasinglulu 
18*91f16700Schasinglulu #include <sunxi_cpucfg.h>
19*91f16700Schasinglulu #include <sunxi_mmap.h>
20*91f16700Schasinglulu #include <sunxi_private.h>
21*91f16700Schasinglulu 
22*91f16700Schasinglulu #ifndef SUNXI_C0_CPU_CTRL_REG
23*91f16700Schasinglulu #define SUNXI_C0_CPU_CTRL_REG(n)	0
24*91f16700Schasinglulu #define SUNXI_CPU_UNK_REG(n)		0
25*91f16700Schasinglulu #define SUNXI_CPU_CTRL_REG(n)		0
26*91f16700Schasinglulu #endif
27*91f16700Schasinglulu 
28*91f16700Schasinglulu static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
29*91f16700Schasinglulu {
30*91f16700Schasinglulu 	if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
31*91f16700Schasinglulu 		return;
32*91f16700Schasinglulu 
33*91f16700Schasinglulu 	VERBOSE("PSCI: Disabling power to cluster %d core %d\n", cluster, core);
34*91f16700Schasinglulu 
35*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff);
36*91f16700Schasinglulu }
37*91f16700Schasinglulu 
38*91f16700Schasinglulu static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core)
39*91f16700Schasinglulu {
40*91f16700Schasinglulu 	if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0)
41*91f16700Schasinglulu 		return;
42*91f16700Schasinglulu 
43*91f16700Schasinglulu 	VERBOSE("PSCI: Enabling power to cluster %d core %d\n", cluster, core);
44*91f16700Schasinglulu 
45*91f16700Schasinglulu 	/* Power enable sequence from original Allwinner sources */
46*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe);
47*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8);
48*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0);
49*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80);
50*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00);
51*91f16700Schasinglulu 	udelay(1);
52*91f16700Schasinglulu }
53*91f16700Schasinglulu 
54*91f16700Schasinglulu /* We can't turn ourself off like this, but it works for other cores. */
55*91f16700Schasinglulu static void sunxi_cpu_off(u_register_t mpidr)
56*91f16700Schasinglulu {
57*91f16700Schasinglulu 	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
58*91f16700Schasinglulu 	unsigned int core    = MPIDR_AFFLVL0_VAL(mpidr);
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	if (sunxi_cpucfg_has_per_cluster_regs()) {
63*91f16700Schasinglulu 		/* Deassert DBGPWRDUP */
64*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
65*91f16700Schasinglulu 		/* Activate the core output clamps, but not for core 0. */
66*91f16700Schasinglulu 		if (core != 0) {
67*91f16700Schasinglulu 			mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster),
68*91f16700Schasinglulu 					BIT(core));
69*91f16700Schasinglulu 		}
70*91f16700Schasinglulu 		/* Assert CPU power-on reset */
71*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
72*91f16700Schasinglulu 		/* Remove power from the CPU */
73*91f16700Schasinglulu 		sunxi_cpu_disable_power(cluster, core);
74*91f16700Schasinglulu 	} else {
75*91f16700Schasinglulu 		/* power down(?) debug core */
76*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
77*91f16700Schasinglulu 		/* ??? Activate the core output clamps, but not for core 0 */
78*91f16700Schasinglulu 		if (core != 0) {
79*91f16700Schasinglulu 			mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
80*91f16700Schasinglulu 		}
81*91f16700Schasinglulu 		/* ??? Assert CPU power-on reset ??? */
82*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
83*91f16700Schasinglulu 		/* Remove power from the CPU */
84*91f16700Schasinglulu 		sunxi_cpu_disable_power(cluster, core);
85*91f16700Schasinglulu 	}
86*91f16700Schasinglulu }
87*91f16700Schasinglulu 
88*91f16700Schasinglulu void sunxi_cpu_on(u_register_t mpidr)
89*91f16700Schasinglulu {
90*91f16700Schasinglulu 	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
91*91f16700Schasinglulu 	unsigned int core    = MPIDR_AFFLVL0_VAL(mpidr);
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	if (sunxi_cpucfg_has_per_cluster_regs()) {
96*91f16700Schasinglulu 		/* Assert CPU core reset */
97*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
98*91f16700Schasinglulu 		/* Assert CPU power-on reset */
99*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
100*91f16700Schasinglulu 		/* Set CPU to start in AArch64 mode */
101*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_AA64nAA32_REG(cluster),
102*91f16700Schasinglulu 				BIT(SUNXI_AA64nAA32_OFFSET + core));
103*91f16700Schasinglulu 		/* Apply power to the CPU */
104*91f16700Schasinglulu 		sunxi_cpu_enable_power(cluster, core);
105*91f16700Schasinglulu 		/* Release the core output clamps */
106*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
107*91f16700Schasinglulu 		/* Deassert CPU power-on reset */
108*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
109*91f16700Schasinglulu 		/* Deassert CPU core reset */
110*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
111*91f16700Schasinglulu 		/* Assert DBGPWRDUP */
112*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
113*91f16700Schasinglulu 	} else {
114*91f16700Schasinglulu 		/* Assert CPU core reset */
115*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
116*91f16700Schasinglulu 		/* ??? Assert CPU power-on reset ??? */
117*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 		/* Set CPU to start in AArch64 mode */
120*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_CPU_CTRL_REG(core), BIT(0));
121*91f16700Schasinglulu 
122*91f16700Schasinglulu 		/* Apply power to the CPU */
123*91f16700Schasinglulu 		sunxi_cpu_enable_power(cluster, core);
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 		/* ??? Release the core output clamps ??? */
126*91f16700Schasinglulu 		mmio_clrbits_32(SUNXI_CPU_UNK_REG(core), BIT(1));
127*91f16700Schasinglulu 		/* ??? Deassert CPU power-on reset ??? */
128*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_CPU_UNK_REG(core), BIT(0));
129*91f16700Schasinglulu 		/* Deassert CPU core reset */
130*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(0));
131*91f16700Schasinglulu 		/* power up(?) debug core */
132*91f16700Schasinglulu 		mmio_setbits_32(SUNXI_C0_CPU_CTRL_REG(core), BIT(8));
133*91f16700Schasinglulu 	}
134*91f16700Schasinglulu }
135*91f16700Schasinglulu 
136*91f16700Schasinglulu void sunxi_cpu_power_off_others(void)
137*91f16700Schasinglulu {
138*91f16700Schasinglulu 	u_register_t self = read_mpidr();
139*91f16700Schasinglulu 	unsigned int cluster;
140*91f16700Schasinglulu 	unsigned int core;
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
143*91f16700Schasinglulu 		for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
144*91f16700Schasinglulu 			u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
145*91f16700Schasinglulu 					     (core    << MPIDR_AFF0_SHIFT) |
146*91f16700Schasinglulu 					     BIT(31);
147*91f16700Schasinglulu 			if (mpidr != self)
148*91f16700Schasinglulu 				sunxi_cpu_off(mpidr);
149*91f16700Schasinglulu 		}
150*91f16700Schasinglulu 	}
151*91f16700Schasinglulu }
152