xref: /aosp_15_r20/external/arm-trusted-firmware/plat/socionext/uniphier/uniphier_psci.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park 
9*54fd6939SJiyong Park #include <arch_helpers.h>
10*54fd6939SJiyong Park #include <common/debug.h>
11*54fd6939SJiyong Park #include <errno.h>
12*54fd6939SJiyong Park #include <lib/mmio.h>
13*54fd6939SJiyong Park #include <lib/psci/psci.h>
14*54fd6939SJiyong Park 
15*54fd6939SJiyong Park #include "uniphier.h"
16*54fd6939SJiyong Park 
17*54fd6939SJiyong Park #define UNIPHIER_ROM_RSV0		0x0
18*54fd6939SJiyong Park 
19*54fd6939SJiyong Park #define UNIPHIER_SLFRSTSEL		0x10
20*54fd6939SJiyong Park #define   UNIPHIER_SLFRSTSEL_MASK		GENMASK(1, 0)
21*54fd6939SJiyong Park #define UNIPHIER_SLFRSTCTL		0x14
22*54fd6939SJiyong Park #define   UNIPHIER_SLFRSTCTL_RST		BIT(0)
23*54fd6939SJiyong Park 
24*54fd6939SJiyong Park #define MPIDR_AFFINITY_INVALID		((u_register_t)-1)
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park static uintptr_t uniphier_rom_rsv_base;
27*54fd6939SJiyong Park static uintptr_t uniphier_slfrst_base;
28*54fd6939SJiyong Park 
29*54fd6939SJiyong Park uintptr_t uniphier_sec_entrypoint;
30*54fd6939SJiyong Park 
31*54fd6939SJiyong Park void uniphier_warmboot_entrypoint(void);
32*54fd6939SJiyong Park void __dead2 uniphier_fake_pwr_down(void);
33*54fd6939SJiyong Park u_register_t uniphier_holding_pen_release;
34*54fd6939SJiyong Park static int uniphier_psci_scp_mode;
35*54fd6939SJiyong Park 
uniphier_psci_pwr_domain_on(u_register_t mpidr)36*54fd6939SJiyong Park static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
37*54fd6939SJiyong Park {
38*54fd6939SJiyong Park 	uniphier_holding_pen_release = mpidr;
39*54fd6939SJiyong Park 	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
40*54fd6939SJiyong Park 			   sizeof(uniphier_holding_pen_release));
41*54fd6939SJiyong Park 
42*54fd6939SJiyong Park 	mmio_write_64(uniphier_rom_rsv_base + UNIPHIER_ROM_RSV0,
43*54fd6939SJiyong Park 		      (uint64_t)&uniphier_warmboot_entrypoint);
44*54fd6939SJiyong Park 	sev();
45*54fd6939SJiyong Park 
46*54fd6939SJiyong Park 	return PSCI_E_SUCCESS;
47*54fd6939SJiyong Park }
48*54fd6939SJiyong Park 
uniphier_psci_pwr_domain_off(const psci_power_state_t * target_state)49*54fd6939SJiyong Park static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
50*54fd6939SJiyong Park {
51*54fd6939SJiyong Park 	uniphier_gic_cpuif_disable();
52*54fd6939SJiyong Park }
53*54fd6939SJiyong Park 
uniphier_psci_pwr_domain_on_finish(const psci_power_state_t * target_state)54*54fd6939SJiyong Park static void uniphier_psci_pwr_domain_on_finish(
55*54fd6939SJiyong Park 					const psci_power_state_t *target_state)
56*54fd6939SJiyong Park {
57*54fd6939SJiyong Park 	uniphier_gic_pcpu_init();
58*54fd6939SJiyong Park 	uniphier_gic_cpuif_enable();
59*54fd6939SJiyong Park 
60*54fd6939SJiyong Park 	uniphier_cci_enable();
61*54fd6939SJiyong Park }
62*54fd6939SJiyong Park 
uniphier_psci_pwr_domain_pwr_down_wfi(const psci_power_state_t * target_state)63*54fd6939SJiyong Park static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
64*54fd6939SJiyong Park 					const psci_power_state_t *target_state)
65*54fd6939SJiyong Park {
66*54fd6939SJiyong Park 	/*
67*54fd6939SJiyong Park 	 * The Boot ROM cannot distinguish warm and cold resets.
68*54fd6939SJiyong Park 	 * Instead of the CPU reset, fake it.
69*54fd6939SJiyong Park 	 */
70*54fd6939SJiyong Park 	uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
71*54fd6939SJiyong Park 	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
72*54fd6939SJiyong Park 			   sizeof(uniphier_holding_pen_release));
73*54fd6939SJiyong Park 
74*54fd6939SJiyong Park 	uniphier_fake_pwr_down();
75*54fd6939SJiyong Park }
76*54fd6939SJiyong Park 
uniphier_self_system_reset(void)77*54fd6939SJiyong Park static void uniphier_self_system_reset(void)
78*54fd6939SJiyong Park {
79*54fd6939SJiyong Park 	mmio_clrbits_32(uniphier_slfrst_base + UNIPHIER_SLFRSTSEL,
80*54fd6939SJiyong Park 			UNIPHIER_SLFRSTSEL_MASK);
81*54fd6939SJiyong Park 	mmio_setbits_32(uniphier_slfrst_base + UNIPHIER_SLFRSTCTL,
82*54fd6939SJiyong Park 			UNIPHIER_SLFRSTCTL_RST);
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park 
uniphier_psci_system_off(void)85*54fd6939SJiyong Park static void __dead2 uniphier_psci_system_off(void)
86*54fd6939SJiyong Park {
87*54fd6939SJiyong Park 	if (uniphier_psci_scp_mode) {
88*54fd6939SJiyong Park 		uniphier_scp_system_off();
89*54fd6939SJiyong Park 	} else {
90*54fd6939SJiyong Park 		NOTICE("SCP is disabled; can't shutdown the system.\n");
91*54fd6939SJiyong Park 		NOTICE("Resetting the system instead.\n");
92*54fd6939SJiyong Park 		uniphier_self_system_reset();
93*54fd6939SJiyong Park 	}
94*54fd6939SJiyong Park 
95*54fd6939SJiyong Park 	wfi();
96*54fd6939SJiyong Park 	ERROR("UniPhier System Off: operation not handled.\n");
97*54fd6939SJiyong Park 	panic();
98*54fd6939SJiyong Park }
99*54fd6939SJiyong Park 
uniphier_psci_system_reset(void)100*54fd6939SJiyong Park static void __dead2 uniphier_psci_system_reset(void)
101*54fd6939SJiyong Park {
102*54fd6939SJiyong Park 	if (uniphier_psci_scp_mode)
103*54fd6939SJiyong Park 		uniphier_scp_system_reset();
104*54fd6939SJiyong Park 	else
105*54fd6939SJiyong Park 		uniphier_self_system_reset();
106*54fd6939SJiyong Park 
107*54fd6939SJiyong Park 	wfi();
108*54fd6939SJiyong Park 	ERROR("UniPhier System Reset: operation not handled.\n");
109*54fd6939SJiyong Park 	panic();
110*54fd6939SJiyong Park }
111*54fd6939SJiyong Park 
112*54fd6939SJiyong Park static const struct plat_psci_ops uniphier_psci_ops = {
113*54fd6939SJiyong Park 	.pwr_domain_on = uniphier_psci_pwr_domain_on,
114*54fd6939SJiyong Park 	.pwr_domain_off = uniphier_psci_pwr_domain_off,
115*54fd6939SJiyong Park 	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
116*54fd6939SJiyong Park 	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
117*54fd6939SJiyong Park 	.system_off = uniphier_psci_system_off,
118*54fd6939SJiyong Park 	.system_reset = uniphier_psci_system_reset,
119*54fd6939SJiyong Park };
120*54fd6939SJiyong Park 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)121*54fd6939SJiyong Park int plat_setup_psci_ops(uintptr_t sec_entrypoint,
122*54fd6939SJiyong Park 			const struct plat_psci_ops **psci_ops)
123*54fd6939SJiyong Park {
124*54fd6939SJiyong Park 	uniphier_sec_entrypoint = sec_entrypoint;
125*54fd6939SJiyong Park 	flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
126*54fd6939SJiyong Park 			   sizeof(uniphier_sec_entrypoint));
127*54fd6939SJiyong Park 
128*54fd6939SJiyong Park 	*psci_ops = &uniphier_psci_ops;
129*54fd6939SJiyong Park 
130*54fd6939SJiyong Park 	return 0;
131*54fd6939SJiyong Park }
132*54fd6939SJiyong Park 
133*54fd6939SJiyong Park struct uniphier_psci_ctrl_base {
134*54fd6939SJiyong Park 	uintptr_t rom_rsv_base;
135*54fd6939SJiyong Park 	uintptr_t slfrst_base;
136*54fd6939SJiyong Park };
137*54fd6939SJiyong Park 
138*54fd6939SJiyong Park static const struct uniphier_psci_ctrl_base uniphier_psci_ctrl_base[] = {
139*54fd6939SJiyong Park 	[UNIPHIER_SOC_LD11] = {
140*54fd6939SJiyong Park 		.rom_rsv_base = 0x59801200,
141*54fd6939SJiyong Park 		.slfrst_base = 0x61843000,
142*54fd6939SJiyong Park 	},
143*54fd6939SJiyong Park 	[UNIPHIER_SOC_LD20] = {
144*54fd6939SJiyong Park 		.rom_rsv_base = 0x59801200,
145*54fd6939SJiyong Park 		.slfrst_base = 0x61843000,
146*54fd6939SJiyong Park 	},
147*54fd6939SJiyong Park 	[UNIPHIER_SOC_PXS3] = {
148*54fd6939SJiyong Park 		.rom_rsv_base = 0x59801200,
149*54fd6939SJiyong Park 		.slfrst_base = 0x61843000,
150*54fd6939SJiyong Park 	},
151*54fd6939SJiyong Park };
152*54fd6939SJiyong Park 
uniphier_psci_init(unsigned int soc)153*54fd6939SJiyong Park void uniphier_psci_init(unsigned int soc)
154*54fd6939SJiyong Park {
155*54fd6939SJiyong Park 	assert(soc < ARRAY_SIZE(uniphier_psci_ctrl_base));
156*54fd6939SJiyong Park 	uniphier_rom_rsv_base = uniphier_psci_ctrl_base[soc].rom_rsv_base;
157*54fd6939SJiyong Park 	uniphier_slfrst_base = uniphier_psci_ctrl_base[soc].slfrst_base;
158*54fd6939SJiyong Park 
159*54fd6939SJiyong Park 	if (uniphier_get_boot_master(soc) == UNIPHIER_BOOT_MASTER_SCP) {
160*54fd6939SJiyong Park 		uniphier_psci_scp_mode = uniphier_scp_is_running();
161*54fd6939SJiyong Park 		flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
162*54fd6939SJiyong Park 				   sizeof(uniphier_psci_scp_mode));
163*54fd6939SJiyong Park 
164*54fd6939SJiyong Park 		if (uniphier_psci_scp_mode)
165*54fd6939SJiyong Park 			uniphier_scp_open_com();
166*54fd6939SJiyong Park 	}
167*54fd6939SJiyong Park }
168