xref: /arm-trusted-firmware/plat/qti/msm8916/msm8916_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net>
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <arch.h>
10*91f16700Schasinglulu #include <arch_helpers.h>
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <drivers/arm/cci.h>
13*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
14*91f16700Schasinglulu #include <drivers/delay_timer.h>
15*91f16700Schasinglulu #include <lib/mmio.h>
16*91f16700Schasinglulu #include <lib/psci/psci.h>
17*91f16700Schasinglulu #include <plat/common/platform.h>
18*91f16700Schasinglulu 
19*91f16700Schasinglulu #include <msm8916_mmap.h>
20*91f16700Schasinglulu #include "msm8916_pm.h"
21*91f16700Schasinglulu 
22*91f16700Schasinglulu /*
23*91f16700Schasinglulu  * On platforms with two clusters the index of the APCS memory region is swapped
24*91f16700Schasinglulu  * compared to the MPIDR cluster affinity level: APCS cluster 0 manages CPUs
25*91f16700Schasinglulu  * with cluster affinity level 1, while APCS cluster 1 manages CPUs with level 0.
26*91f16700Schasinglulu  *
27*91f16700Schasinglulu  * On platforms with a single cluster there is only one APCS memory region.
28*91f16700Schasinglulu  */
29*91f16700Schasinglulu #if PLATFORM_CLUSTER_COUNT == 2
30*91f16700Schasinglulu #define MPIDR_APCS_CLUSTER(mpidr)	!MPIDR_AFFLVL1_VAL(mpidr)
31*91f16700Schasinglulu #else
32*91f16700Schasinglulu #define MPIDR_APCS_CLUSTER(mpidr)	0
33*91f16700Schasinglulu #endif
34*91f16700Schasinglulu 
35*91f16700Schasinglulu #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
36*91f16700Schasinglulu 
37*91f16700Schasinglulu static int msm8916_pwr_domain_on(u_register_t mpidr)
38*91f16700Schasinglulu {
39*91f16700Schasinglulu 	/* Should be never called on single-core platforms */
40*91f16700Schasinglulu 	if (PLATFORM_CORE_COUNT == 1) {
41*91f16700Schasinglulu 		assert(false);
42*91f16700Schasinglulu 		return PSCI_E_ALREADY_ON;
43*91f16700Schasinglulu 	}
44*91f16700Schasinglulu 
45*91f16700Schasinglulu 	/* Power on L2 cache and secondary CPU core for the first time */
46*91f16700Schasinglulu 	if (PLATFORM_CLUSTER_COUNT > 1) {
47*91f16700Schasinglulu 		msm8916_l2_boot(APCS_GLB(MPIDR_APCS_CLUSTER(mpidr)));
48*91f16700Schasinglulu 	}
49*91f16700Schasinglulu 	msm8916_cpu_boot(APCS_ALIAS_ACS(MPIDR_APCS_CLUSTER(mpidr),
50*91f16700Schasinglulu 					MPIDR_AFFLVL0_VAL(mpidr)));
51*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
52*91f16700Schasinglulu }
53*91f16700Schasinglulu 
54*91f16700Schasinglulu static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state)
55*91f16700Schasinglulu {
56*91f16700Schasinglulu 	/* Should be never called on single-core platforms */
57*91f16700Schasinglulu 	if (PLATFORM_CORE_COUNT == 1) {
58*91f16700Schasinglulu 		assert(false);
59*91f16700Schasinglulu 		return;
60*91f16700Schasinglulu 	}
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	if (PLATFORM_CLUSTER_COUNT > 1 &&
63*91f16700Schasinglulu 	    CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
64*91f16700Schasinglulu 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
65*91f16700Schasinglulu 	}
66*91f16700Schasinglulu 
67*91f16700Schasinglulu 	gicv2_pcpu_distif_init();
68*91f16700Schasinglulu 	gicv2_cpuif_enable();
69*91f16700Schasinglulu }
70*91f16700Schasinglulu 
71*91f16700Schasinglulu static void __dead2 msm8916_system_reset(void)
72*91f16700Schasinglulu {
73*91f16700Schasinglulu 	mmio_write_32(MPM_PS_HOLD, 0);
74*91f16700Schasinglulu 	mdelay(1000);
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 	ERROR("PSCI: System reset failed\n");
77*91f16700Schasinglulu 	panic();
78*91f16700Schasinglulu }
79*91f16700Schasinglulu 
80*91f16700Schasinglulu static const plat_psci_ops_t msm8916_psci_ops = {
81*91f16700Schasinglulu 	.pwr_domain_on			= msm8916_pwr_domain_on,
82*91f16700Schasinglulu 	.pwr_domain_on_finish		= msm8916_pwr_domain_on_finish,
83*91f16700Schasinglulu 	.system_off			= msm8916_system_reset,
84*91f16700Schasinglulu 	.system_reset			= msm8916_system_reset,
85*91f16700Schasinglulu };
86*91f16700Schasinglulu 
87*91f16700Schasinglulu /* Defined and used in msm8916_helpers.S */
88*91f16700Schasinglulu extern uintptr_t msm8916_entry_point;
89*91f16700Schasinglulu 
90*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint,
91*91f16700Schasinglulu 			const plat_psci_ops_t **psci_ops)
92*91f16700Schasinglulu {
93*91f16700Schasinglulu 	/*
94*91f16700Schasinglulu 	 * The entry point is read with caches off (and even from two different
95*91f16700Schasinglulu 	 * physical addresses when read through the "boot remapper"), so make
96*91f16700Schasinglulu 	 * sure it is flushed to memory.
97*91f16700Schasinglulu 	 */
98*91f16700Schasinglulu 	msm8916_entry_point = sec_entrypoint;
99*91f16700Schasinglulu 	flush_dcache_range((uintptr_t)&msm8916_entry_point, sizeof(uintptr_t));
100*91f16700Schasinglulu 
101*91f16700Schasinglulu 	*psci_ops = &msm8916_psci_ops;
102*91f16700Schasinglulu 	return 0;
103*91f16700Schasinglulu }
104