xref: /rk3399_ARM-atf/plat/qti/msm8916/msm8916_pm.c (revision d1b5ada8887c767c39eceaf816eefbf303e0dcd8)
1dddba19aSStephan Gerhold /*
201ba69cdSStephan Gerhold  * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net>
3dddba19aSStephan Gerhold  *
4dddba19aSStephan Gerhold  * SPDX-License-Identifier: BSD-3-Clause
5dddba19aSStephan Gerhold  */
6dddba19aSStephan Gerhold 
7*d9e565eaSStephan Gerhold #include <assert.h>
8*d9e565eaSStephan Gerhold 
9dddba19aSStephan Gerhold #include <arch.h>
1001ba69cdSStephan Gerhold #include <arch_helpers.h>
11dddba19aSStephan Gerhold #include <common/debug.h>
121240dc7eSStephan Gerhold #include <drivers/arm/cci.h>
13a758c0b6SStephan Gerhold #include <drivers/arm/gicv2.h>
14dddba19aSStephan Gerhold #include <drivers/delay_timer.h>
15dddba19aSStephan Gerhold #include <lib/mmio.h>
16dddba19aSStephan Gerhold #include <lib/psci/psci.h>
17dddba19aSStephan Gerhold #include <plat/common/platform.h>
18dddba19aSStephan Gerhold 
19dddba19aSStephan Gerhold #include <msm8916_mmap.h>
20a758c0b6SStephan Gerhold #include "msm8916_pm.h"
21a758c0b6SStephan Gerhold 
221d7ed58fSStephan Gerhold /*
231d7ed58fSStephan Gerhold  * On platforms with two clusters the index of the APCS memory region is swapped
241d7ed58fSStephan Gerhold  * compared to the MPIDR cluster affinity level: APCS cluster 0 manages CPUs
251d7ed58fSStephan Gerhold  * with cluster affinity level 1, while APCS cluster 1 manages CPUs with level 0.
261d7ed58fSStephan Gerhold  *
271d7ed58fSStephan Gerhold  * On platforms with a single cluster there is only one APCS memory region.
281d7ed58fSStephan Gerhold  */
291d7ed58fSStephan Gerhold #if PLATFORM_CLUSTER_COUNT == 2
301d7ed58fSStephan Gerhold #define MPIDR_APCS_CLUSTER(mpidr)	!MPIDR_AFFLVL1_VAL(mpidr)
311d7ed58fSStephan Gerhold #else
321d7ed58fSStephan Gerhold #define MPIDR_APCS_CLUSTER(mpidr)	0
331d7ed58fSStephan Gerhold #endif
341d7ed58fSStephan Gerhold 
351240dc7eSStephan Gerhold #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
361240dc7eSStephan Gerhold 
msm8916_pwr_domain_on(u_register_t mpidr)37a758c0b6SStephan Gerhold static int msm8916_pwr_domain_on(u_register_t mpidr)
38a758c0b6SStephan Gerhold {
39*d9e565eaSStephan Gerhold 	/* Should be never called on single-core platforms */
40*d9e565eaSStephan Gerhold 	if (PLATFORM_CORE_COUNT == 1) {
41*d9e565eaSStephan Gerhold 		assert(false);
42*d9e565eaSStephan Gerhold 		return PSCI_E_ALREADY_ON;
43*d9e565eaSStephan Gerhold 	}
44*d9e565eaSStephan Gerhold 
45c822d265SStephan Gerhold 	/* Power on L2 cache and secondary CPU core for the first time */
46c822d265SStephan Gerhold 	if (PLATFORM_CLUSTER_COUNT > 1) {
47c822d265SStephan Gerhold 		msm8916_l2_boot(APCS_GLB(MPIDR_APCS_CLUSTER(mpidr)));
48c822d265SStephan Gerhold 	}
491d7ed58fSStephan Gerhold 	msm8916_cpu_boot(APCS_ALIAS_ACS(MPIDR_APCS_CLUSTER(mpidr),
501d7ed58fSStephan Gerhold 					MPIDR_AFFLVL0_VAL(mpidr)));
51a758c0b6SStephan Gerhold 	return PSCI_E_SUCCESS;
52a758c0b6SStephan Gerhold }
53a758c0b6SStephan Gerhold 
msm8916_pwr_domain_on_finish(const psci_power_state_t * target_state)54a758c0b6SStephan Gerhold static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state)
55a758c0b6SStephan Gerhold {
56*d9e565eaSStephan Gerhold 	/* Should be never called on single-core platforms */
57*d9e565eaSStephan Gerhold 	if (PLATFORM_CORE_COUNT == 1) {
58*d9e565eaSStephan Gerhold 		assert(false);
59*d9e565eaSStephan Gerhold 		return;
60*d9e565eaSStephan Gerhold 	}
61*d9e565eaSStephan Gerhold 
621240dc7eSStephan Gerhold 	if (PLATFORM_CLUSTER_COUNT > 1 &&
631240dc7eSStephan Gerhold 	    CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
641240dc7eSStephan Gerhold 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
651240dc7eSStephan Gerhold 	}
661240dc7eSStephan Gerhold 
67a758c0b6SStephan Gerhold 	gicv2_pcpu_distif_init();
68a758c0b6SStephan Gerhold 	gicv2_cpuif_enable();
69a758c0b6SStephan Gerhold }
70dddba19aSStephan Gerhold 
msm8916_system_reset(void)71dddba19aSStephan Gerhold static void __dead2 msm8916_system_reset(void)
72dddba19aSStephan Gerhold {
73dddba19aSStephan Gerhold 	mmio_write_32(MPM_PS_HOLD, 0);
74dddba19aSStephan Gerhold 	mdelay(1000);
75dddba19aSStephan Gerhold 
76dddba19aSStephan Gerhold 	ERROR("PSCI: System reset failed\n");
77dddba19aSStephan Gerhold 	panic();
78dddba19aSStephan Gerhold }
79dddba19aSStephan Gerhold 
80dddba19aSStephan Gerhold static const plat_psci_ops_t msm8916_psci_ops = {
81a758c0b6SStephan Gerhold 	.pwr_domain_on			= msm8916_pwr_domain_on,
82a758c0b6SStephan Gerhold 	.pwr_domain_on_finish		= msm8916_pwr_domain_on_finish,
83dddba19aSStephan Gerhold 	.system_off			= msm8916_system_reset,
84dddba19aSStephan Gerhold 	.system_reset			= msm8916_system_reset,
85dddba19aSStephan Gerhold };
86dddba19aSStephan Gerhold 
87dddba19aSStephan Gerhold /* Defined and used in msm8916_helpers.S */
88dddba19aSStephan Gerhold extern uintptr_t msm8916_entry_point;
89dddba19aSStephan Gerhold 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)90dddba19aSStephan Gerhold int plat_setup_psci_ops(uintptr_t sec_entrypoint,
91dddba19aSStephan Gerhold 			const plat_psci_ops_t **psci_ops)
92dddba19aSStephan Gerhold {
9301ba69cdSStephan Gerhold 	/*
9401ba69cdSStephan Gerhold 	 * The entry point is read with caches off (and even from two different
9501ba69cdSStephan Gerhold 	 * physical addresses when read through the "boot remapper"), so make
9601ba69cdSStephan Gerhold 	 * sure it is flushed to memory.
9701ba69cdSStephan Gerhold 	 */
98dddba19aSStephan Gerhold 	msm8916_entry_point = sec_entrypoint;
9901ba69cdSStephan Gerhold 	flush_dcache_range((uintptr_t)&msm8916_entry_point, sizeof(uintptr_t));
10001ba69cdSStephan Gerhold 
101dddba19aSStephan Gerhold 	*psci_ops = &msm8916_psci_ops;
102dddba19aSStephan Gerhold 	return 0;
103dddba19aSStephan Gerhold }
104