blob: 7b44d60398e227372a17af4c180b85708cd57fae [file] [log] [blame]
Stephan Gerhold14fdf072021-12-01 20:01:11 +01001/*
Stephan Gerholddd2c8f72022-09-17 18:21:20 +02002 * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net>
Stephan Gerhold14fdf072021-12-01 20:01:11 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
Stephan Gerholddd2c8f72022-09-17 18:21:20 +02008#include <arch_helpers.h>
Stephan Gerhold14fdf072021-12-01 20:01:11 +01009#include <common/debug.h>
Stephan Gerhold1b783462022-09-16 20:42:49 +020010#include <drivers/arm/cci.h>
Stephan Gerhold765e8592021-12-01 20:04:44 +010011#include <drivers/arm/gicv2.h>
Stephan Gerhold14fdf072021-12-01 20:01:11 +010012#include <drivers/delay_timer.h>
13#include <lib/mmio.h>
14#include <lib/psci/psci.h>
15#include <plat/common/platform.h>
16
17#include <msm8916_mmap.h>
Stephan Gerhold765e8592021-12-01 20:04:44 +010018#include "msm8916_pm.h"
19
Stephan Gerholdf0ed7282022-09-16 10:45:19 +020020/*
21 * On platforms with two clusters the index of the APCS memory region is swapped
22 * compared to the MPIDR cluster affinity level: APCS cluster 0 manages CPUs
23 * with cluster affinity level 1, while APCS cluster 1 manages CPUs with level 0.
24 *
25 * On platforms with a single cluster there is only one APCS memory region.
26 */
27#if PLATFORM_CLUSTER_COUNT == 2
28#define MPIDR_APCS_CLUSTER(mpidr) !MPIDR_AFFLVL1_VAL(mpidr)
29#else
30#define MPIDR_APCS_CLUSTER(mpidr) 0
31#endif
32
Stephan Gerhold1b783462022-09-16 20:42:49 +020033#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
34
Stephan Gerhold765e8592021-12-01 20:04:44 +010035static int msm8916_pwr_domain_on(u_register_t mpidr)
36{
Stephan Gerhold4dfdc5f2022-09-16 10:45:19 +020037 /* Power on L2 cache and secondary CPU core for the first time */
38 if (PLATFORM_CLUSTER_COUNT > 1) {
39 msm8916_l2_boot(APCS_GLB(MPIDR_APCS_CLUSTER(mpidr)));
40 }
Stephan Gerholdf0ed7282022-09-16 10:45:19 +020041 msm8916_cpu_boot(APCS_ALIAS_ACS(MPIDR_APCS_CLUSTER(mpidr),
42 MPIDR_AFFLVL0_VAL(mpidr)));
Stephan Gerhold765e8592021-12-01 20:04:44 +010043 return PSCI_E_SUCCESS;
44}
45
46static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state)
47{
Stephan Gerhold1b783462022-09-16 20:42:49 +020048 if (PLATFORM_CLUSTER_COUNT > 1 &&
49 CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
50 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
51 }
52
Stephan Gerhold765e8592021-12-01 20:04:44 +010053 gicv2_pcpu_distif_init();
54 gicv2_cpuif_enable();
55}
Stephan Gerhold14fdf072021-12-01 20:01:11 +010056
57static void __dead2 msm8916_system_reset(void)
58{
59 mmio_write_32(MPM_PS_HOLD, 0);
60 mdelay(1000);
61
62 ERROR("PSCI: System reset failed\n");
63 panic();
64}
65
66static const plat_psci_ops_t msm8916_psci_ops = {
Stephan Gerhold765e8592021-12-01 20:04:44 +010067 .pwr_domain_on = msm8916_pwr_domain_on,
68 .pwr_domain_on_finish = msm8916_pwr_domain_on_finish,
Stephan Gerhold14fdf072021-12-01 20:01:11 +010069 .system_off = msm8916_system_reset,
70 .system_reset = msm8916_system_reset,
71};
72
73/* Defined and used in msm8916_helpers.S */
74extern uintptr_t msm8916_entry_point;
75
76int plat_setup_psci_ops(uintptr_t sec_entrypoint,
77 const plat_psci_ops_t **psci_ops)
78{
Stephan Gerholddd2c8f72022-09-17 18:21:20 +020079 /*
80 * The entry point is read with caches off (and even from two different
81 * physical addresses when read through the "boot remapper"), so make
82 * sure it is flushed to memory.
83 */
Stephan Gerhold14fdf072021-12-01 20:01:11 +010084 msm8916_entry_point = sec_entrypoint;
Stephan Gerholddd2c8f72022-09-17 18:21:20 +020085 flush_dcache_range((uintptr_t)&msm8916_entry_point, sizeof(uintptr_t));
86
Stephan Gerhold14fdf072021-12-01 20:01:11 +010087 *psci_ops = &msm8916_psci_ops;
88 return 0;
89}