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