19a40c0fbSSheetal Tigadoli /*
29a40c0fbSSheetal Tigadoli * Copyright (c) 2017 - 2020, Broadcom
39a40c0fbSSheetal Tigadoli *
49a40c0fbSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause
59a40c0fbSSheetal Tigadoli */
69a40c0fbSSheetal Tigadoli
79a40c0fbSSheetal Tigadoli #include <assert.h>
89a40c0fbSSheetal Tigadoli #include <errno.h>
9*4ef449c1SManish Pandey #include <inttypes.h>
109a40c0fbSSheetal Tigadoli
119a40c0fbSSheetal Tigadoli #include <arch_helpers.h>
129a40c0fbSSheetal Tigadoli #include <common/debug.h>
139a40c0fbSSheetal Tigadoli #include <drivers/arm/ccn.h>
149a40c0fbSSheetal Tigadoli #include <lib/bakery_lock.h>
159a40c0fbSSheetal Tigadoli #include <lib/mmio.h>
169a40c0fbSSheetal Tigadoli #include <lib/psci/psci.h>
179a40c0fbSSheetal Tigadoli #include <lib/spinlock.h>
189a40c0fbSSheetal Tigadoli
199a40c0fbSSheetal Tigadoli #include <brcm_scpi.h>
203942d3a8SSheetal Tigadoli #include <chimp.h>
219a40c0fbSSheetal Tigadoli #include <cmn_plat_util.h>
229a40c0fbSSheetal Tigadoli #include <plat_brcm.h>
239a40c0fbSSheetal Tigadoli #include <platform_def.h>
243942d3a8SSheetal Tigadoli #include <sr_utils.h>
259a40c0fbSSheetal Tigadoli
269a40c0fbSSheetal Tigadoli #include "m0_cfg.h"
279a40c0fbSSheetal Tigadoli
289a40c0fbSSheetal Tigadoli
299a40c0fbSSheetal Tigadoli #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
309a40c0fbSSheetal Tigadoli #define CLUSTER_PWR_STATE(state) \
319a40c0fbSSheetal Tigadoli ((state)->pwr_domain_state[MPIDR_AFFLVL1])
329a40c0fbSSheetal Tigadoli #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL2])
339a40c0fbSSheetal Tigadoli
349a40c0fbSSheetal Tigadoli #define VENDOR_RST_TYPE_SHIFT 4
359a40c0fbSSheetal Tigadoli
369a40c0fbSSheetal Tigadoli #if HW_ASSISTED_COHERENCY
379a40c0fbSSheetal Tigadoli /*
389a40c0fbSSheetal Tigadoli * On systems where participant CPUs are cache-coherent, we can use spinlocks
399a40c0fbSSheetal Tigadoli * instead of bakery locks.
409a40c0fbSSheetal Tigadoli */
419a40c0fbSSheetal Tigadoli spinlock_t event_lock;
429a40c0fbSSheetal Tigadoli #define event_lock_get(_lock) spin_lock(&_lock)
439a40c0fbSSheetal Tigadoli #define event_lock_release(_lock) spin_unlock(&_lock)
449a40c0fbSSheetal Tigadoli
459a40c0fbSSheetal Tigadoli #else
469a40c0fbSSheetal Tigadoli /*
479a40c0fbSSheetal Tigadoli * Use bakery locks for state coordination as not all participants are
489a40c0fbSSheetal Tigadoli * cache coherent now.
499a40c0fbSSheetal Tigadoli */
509a40c0fbSSheetal Tigadoli DEFINE_BAKERY_LOCK(event_lock);
519a40c0fbSSheetal Tigadoli #define event_lock_get(_lock) bakery_lock_get(&_lock)
529a40c0fbSSheetal Tigadoli #define event_lock_release(_lock) bakery_lock_release(&_lock)
539a40c0fbSSheetal Tigadoli #endif
549a40c0fbSSheetal Tigadoli
brcm_pwr_domain_on(u_register_t mpidr)559a40c0fbSSheetal Tigadoli static int brcm_pwr_domain_on(u_register_t mpidr)
569a40c0fbSSheetal Tigadoli {
579a40c0fbSSheetal Tigadoli /*
589a40c0fbSSheetal Tigadoli * SCP takes care of powering up parent power domains so we
599a40c0fbSSheetal Tigadoli * only need to care about level 0
609a40c0fbSSheetal Tigadoli */
619a40c0fbSSheetal Tigadoli scpi_set_brcm_power_state(mpidr, scpi_power_on, scpi_power_on,
629a40c0fbSSheetal Tigadoli scpi_power_on);
639a40c0fbSSheetal Tigadoli
649a40c0fbSSheetal Tigadoli return PSCI_E_SUCCESS;
659a40c0fbSSheetal Tigadoli }
669a40c0fbSSheetal Tigadoli
679a40c0fbSSheetal Tigadoli /*******************************************************************************
689a40c0fbSSheetal Tigadoli * Handler called when a power level has just been powered on after
699a40c0fbSSheetal Tigadoli * being turned off earlier. The target_state encodes the low power state that
709a40c0fbSSheetal Tigadoli * each level has woken up from. This handler would never be invoked with
719a40c0fbSSheetal Tigadoli * the system power domain uninitialized as either the primary would have taken
729a40c0fbSSheetal Tigadoli * care of it as part of cold boot or the first core awakened from system
739a40c0fbSSheetal Tigadoli * suspend would have already initialized it.
749a40c0fbSSheetal Tigadoli ******************************************************************************/
brcm_pwr_domain_on_finish(const psci_power_state_t * target_state)759a40c0fbSSheetal Tigadoli static void brcm_pwr_domain_on_finish(const psci_power_state_t *target_state)
769a40c0fbSSheetal Tigadoli {
779a40c0fbSSheetal Tigadoli unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
789a40c0fbSSheetal Tigadoli
799a40c0fbSSheetal Tigadoli /* Assert that the system power domain need not be initialized */
809a40c0fbSSheetal Tigadoli assert(SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_RUN);
819a40c0fbSSheetal Tigadoli
829a40c0fbSSheetal Tigadoli assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
839a40c0fbSSheetal Tigadoli
849a40c0fbSSheetal Tigadoli /*
859a40c0fbSSheetal Tigadoli * Perform the common cluster specific operations i.e enable coherency
869a40c0fbSSheetal Tigadoli * if this cluster was off.
879a40c0fbSSheetal Tigadoli */
889a40c0fbSSheetal Tigadoli if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) {
899a40c0fbSSheetal Tigadoli INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id);
909a40c0fbSSheetal Tigadoli ccn_enter_snoop_dvm_domain(1 << cluster_id);
919a40c0fbSSheetal Tigadoli }
929a40c0fbSSheetal Tigadoli
939a40c0fbSSheetal Tigadoli /* Program the gic per-cpu distributor or re-distributor interface */
949a40c0fbSSheetal Tigadoli plat_brcm_gic_pcpu_init();
959a40c0fbSSheetal Tigadoli
969a40c0fbSSheetal Tigadoli /* Enable the gic cpu interface */
979a40c0fbSSheetal Tigadoli plat_brcm_gic_cpuif_enable();
989a40c0fbSSheetal Tigadoli }
999a40c0fbSSheetal Tigadoli
brcm_power_down_common(void)1009a40c0fbSSheetal Tigadoli static void brcm_power_down_common(void)
1019a40c0fbSSheetal Tigadoli {
1029a40c0fbSSheetal Tigadoli unsigned int standbywfil2, standbywfi;
1039a40c0fbSSheetal Tigadoli uint64_t mpidr = read_mpidr_el1();
1049a40c0fbSSheetal Tigadoli
1059a40c0fbSSheetal Tigadoli switch (MPIDR_AFFLVL1_VAL(mpidr)) {
1069a40c0fbSSheetal Tigadoli case 0x0:
1079a40c0fbSSheetal Tigadoli standbywfi = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI;
1089a40c0fbSSheetal Tigadoli standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2;
1099a40c0fbSSheetal Tigadoli break;
1109a40c0fbSSheetal Tigadoli case 0x1:
1119a40c0fbSSheetal Tigadoli standbywfi = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI;
1129a40c0fbSSheetal Tigadoli standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2;
1139a40c0fbSSheetal Tigadoli break;
1149a40c0fbSSheetal Tigadoli case 0x2:
1159a40c0fbSSheetal Tigadoli standbywfi = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI;
1169a40c0fbSSheetal Tigadoli standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2;
1179a40c0fbSSheetal Tigadoli break;
1189a40c0fbSSheetal Tigadoli case 0x3:
1199a40c0fbSSheetal Tigadoli standbywfi = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI;
1209a40c0fbSSheetal Tigadoli standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2;
1219a40c0fbSSheetal Tigadoli break;
1229a40c0fbSSheetal Tigadoli default:
123*4ef449c1SManish Pandey ERROR("Invalid cluster #%" PRIx64 "\n", MPIDR_AFFLVL1_VAL(mpidr));
1249a40c0fbSSheetal Tigadoli return;
1259a40c0fbSSheetal Tigadoli }
1269a40c0fbSSheetal Tigadoli /* Clear the WFI status bit */
1279a40c0fbSSheetal Tigadoli event_lock_get(event_lock);
1289a40c0fbSSheetal Tigadoli mmio_setbits_32(CDRU_PROC_EVENT_CLEAR,
1299a40c0fbSSheetal Tigadoli (1 << (standbywfi + MPIDR_AFFLVL0_VAL(mpidr))) |
1309a40c0fbSSheetal Tigadoli (1 << standbywfil2));
1319a40c0fbSSheetal Tigadoli event_lock_release(event_lock);
1329a40c0fbSSheetal Tigadoli }
1339a40c0fbSSheetal Tigadoli
1349a40c0fbSSheetal Tigadoli /*
1359a40c0fbSSheetal Tigadoli * Helper function to inform power down state to SCP.
1369a40c0fbSSheetal Tigadoli */
brcm_scp_suspend(const psci_power_state_t * target_state)1379a40c0fbSSheetal Tigadoli static void brcm_scp_suspend(const psci_power_state_t *target_state)
1389a40c0fbSSheetal Tigadoli {
1399a40c0fbSSheetal Tigadoli uint32_t cluster_state = scpi_power_on;
1409a40c0fbSSheetal Tigadoli uint32_t system_state = scpi_power_on;
1419a40c0fbSSheetal Tigadoli
1429a40c0fbSSheetal Tigadoli /* Check if power down at system power domain level is requested */
1439a40c0fbSSheetal Tigadoli if (SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
1449a40c0fbSSheetal Tigadoli system_state = scpi_power_retention;
1459a40c0fbSSheetal Tigadoli
1469a40c0fbSSheetal Tigadoli /* Check if Cluster is to be turned off */
1479a40c0fbSSheetal Tigadoli if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
1489a40c0fbSSheetal Tigadoli cluster_state = scpi_power_off;
1499a40c0fbSSheetal Tigadoli
1509a40c0fbSSheetal Tigadoli /*
1519a40c0fbSSheetal Tigadoli * Ask the SCP to power down the appropriate components depending upon
1529a40c0fbSSheetal Tigadoli * their state.
1539a40c0fbSSheetal Tigadoli */
1549a40c0fbSSheetal Tigadoli scpi_set_brcm_power_state(read_mpidr_el1(),
1559a40c0fbSSheetal Tigadoli scpi_power_off,
1569a40c0fbSSheetal Tigadoli cluster_state,
1579a40c0fbSSheetal Tigadoli system_state);
1589a40c0fbSSheetal Tigadoli }
1599a40c0fbSSheetal Tigadoli
1609a40c0fbSSheetal Tigadoli /*
1619a40c0fbSSheetal Tigadoli * Helper function to turn off a CPU power domain and its parent power domains
1629a40c0fbSSheetal Tigadoli * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
1639a40c0fbSSheetal Tigadoli * call the suspend helper here.
1649a40c0fbSSheetal Tigadoli */
brcm_scp_off(const psci_power_state_t * target_state)1659a40c0fbSSheetal Tigadoli static void brcm_scp_off(const psci_power_state_t *target_state)
1669a40c0fbSSheetal Tigadoli {
1679a40c0fbSSheetal Tigadoli brcm_scp_suspend(target_state);
1689a40c0fbSSheetal Tigadoli }
1699a40c0fbSSheetal Tigadoli
brcm_pwr_domain_off(const psci_power_state_t * target_state)1709a40c0fbSSheetal Tigadoli static void brcm_pwr_domain_off(const psci_power_state_t *target_state)
1719a40c0fbSSheetal Tigadoli {
1729a40c0fbSSheetal Tigadoli unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
1739a40c0fbSSheetal Tigadoli
1749a40c0fbSSheetal Tigadoli assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
1759a40c0fbSSheetal Tigadoli /* Prevent interrupts from spuriously waking up this cpu */
1769a40c0fbSSheetal Tigadoli plat_brcm_gic_cpuif_disable();
1779a40c0fbSSheetal Tigadoli
1789a40c0fbSSheetal Tigadoli /* Turn redistributor off */
1799a40c0fbSSheetal Tigadoli plat_brcm_gic_redistif_off();
1809a40c0fbSSheetal Tigadoli
1819a40c0fbSSheetal Tigadoli /* If Cluster is to be turned off, disable coherency */
1829a40c0fbSSheetal Tigadoli if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
1839a40c0fbSSheetal Tigadoli ccn_exit_snoop_dvm_domain(1 << cluster_id);
1849a40c0fbSSheetal Tigadoli
1859a40c0fbSSheetal Tigadoli brcm_power_down_common();
1869a40c0fbSSheetal Tigadoli
1879a40c0fbSSheetal Tigadoli brcm_scp_off(target_state);
1889a40c0fbSSheetal Tigadoli }
1899a40c0fbSSheetal Tigadoli
1909a40c0fbSSheetal Tigadoli /*******************************************************************************
1919a40c0fbSSheetal Tigadoli * Handler called when the CPU power domain is about to enter standby.
1929a40c0fbSSheetal Tigadoli ******************************************************************************/
brcm_cpu_standby(plat_local_state_t cpu_state)1939a40c0fbSSheetal Tigadoli static void brcm_cpu_standby(plat_local_state_t cpu_state)
1949a40c0fbSSheetal Tigadoli {
1959a40c0fbSSheetal Tigadoli unsigned int scr;
1969a40c0fbSSheetal Tigadoli
1979a40c0fbSSheetal Tigadoli assert(cpu_state == PLAT_LOCAL_STATE_RET);
1989a40c0fbSSheetal Tigadoli
1999a40c0fbSSheetal Tigadoli scr = read_scr_el3();
2009a40c0fbSSheetal Tigadoli /*
2019a40c0fbSSheetal Tigadoli * Enable the Non secure interrupt to wake the CPU.
2029a40c0fbSSheetal Tigadoli * In GICv3 affinity routing mode, the non secure group1 interrupts use
2039a40c0fbSSheetal Tigadoli * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ.
2049a40c0fbSSheetal Tigadoli * Enabling both the bits works for both GICv2 mode and GICv3 affinity
2059a40c0fbSSheetal Tigadoli * routing mode.
2069a40c0fbSSheetal Tigadoli */
2079a40c0fbSSheetal Tigadoli write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
2089a40c0fbSSheetal Tigadoli isb();
2099a40c0fbSSheetal Tigadoli dsb();
2109a40c0fbSSheetal Tigadoli wfi();
2119a40c0fbSSheetal Tigadoli
2129a40c0fbSSheetal Tigadoli /*
2139a40c0fbSSheetal Tigadoli * Restore SCR to the original value, synchronisation of scr_el3 is
2149a40c0fbSSheetal Tigadoli * done by eret while el3_exit to save some execution cycles.
2159a40c0fbSSheetal Tigadoli */
2169a40c0fbSSheetal Tigadoli write_scr_el3(scr);
2179a40c0fbSSheetal Tigadoli }
2189a40c0fbSSheetal Tigadoli
2199a40c0fbSSheetal Tigadoli /*
2209a40c0fbSSheetal Tigadoli * Helper function to shutdown the system via SCPI.
2219a40c0fbSSheetal Tigadoli */
brcm_scp_sys_shutdown(void)2229a40c0fbSSheetal Tigadoli static void __dead2 brcm_scp_sys_shutdown(void)
2239a40c0fbSSheetal Tigadoli {
2249a40c0fbSSheetal Tigadoli /*
2259a40c0fbSSheetal Tigadoli * Disable GIC CPU interface to prevent pending interrupt
2269a40c0fbSSheetal Tigadoli * from waking up the AP from WFI.
2279a40c0fbSSheetal Tigadoli */
2289a40c0fbSSheetal Tigadoli plat_brcm_gic_cpuif_disable();
2299a40c0fbSSheetal Tigadoli
2309a40c0fbSSheetal Tigadoli /* Flush and invalidate data cache */
2319a40c0fbSSheetal Tigadoli dcsw_op_all(DCCISW);
2329a40c0fbSSheetal Tigadoli
2339a40c0fbSSheetal Tigadoli /* Bring Cluster out of coherency domain as its going to die */
2349a40c0fbSSheetal Tigadoli plat_brcm_interconnect_exit_coherency();
2359a40c0fbSSheetal Tigadoli
2369a40c0fbSSheetal Tigadoli brcm_power_down_common();
2379a40c0fbSSheetal Tigadoli
2389a40c0fbSSheetal Tigadoli /* Send the power down request to the SCP */
2399a40c0fbSSheetal Tigadoli scpi_sys_power_state(scpi_system_shutdown);
2409a40c0fbSSheetal Tigadoli
2419a40c0fbSSheetal Tigadoli wfi();
2429a40c0fbSSheetal Tigadoli ERROR("BRCM System Off: operation not handled.\n");
2439a40c0fbSSheetal Tigadoli panic();
2449a40c0fbSSheetal Tigadoli }
2459a40c0fbSSheetal Tigadoli
2469a40c0fbSSheetal Tigadoli /*
2479a40c0fbSSheetal Tigadoli * Helper function to reset the system
2489a40c0fbSSheetal Tigadoli */
brcm_scp_sys_reset(unsigned int reset_type)2499a40c0fbSSheetal Tigadoli static void __dead2 brcm_scp_sys_reset(unsigned int reset_type)
2509a40c0fbSSheetal Tigadoli {
2519a40c0fbSSheetal Tigadoli /*
2529a40c0fbSSheetal Tigadoli * Disable GIC CPU interface to prevent pending interrupt
2539a40c0fbSSheetal Tigadoli * from waking up the AP from WFI.
2549a40c0fbSSheetal Tigadoli */
2559a40c0fbSSheetal Tigadoli plat_brcm_gic_cpuif_disable();
2569a40c0fbSSheetal Tigadoli
2579a40c0fbSSheetal Tigadoli /* Flush and invalidate data cache */
2589a40c0fbSSheetal Tigadoli dcsw_op_all(DCCISW);
2599a40c0fbSSheetal Tigadoli
2609a40c0fbSSheetal Tigadoli /* Bring Cluster out of coherency domain as its going to die */
2619a40c0fbSSheetal Tigadoli plat_brcm_interconnect_exit_coherency();
2629a40c0fbSSheetal Tigadoli
2639a40c0fbSSheetal Tigadoli brcm_power_down_common();
2649a40c0fbSSheetal Tigadoli
2659a40c0fbSSheetal Tigadoli /* Send the system reset request to the SCP
2669a40c0fbSSheetal Tigadoli *
2679a40c0fbSSheetal Tigadoli * As per PSCI spec system power state could be
2689a40c0fbSSheetal Tigadoli * 0-> Shutdown
2699a40c0fbSSheetal Tigadoli * 1-> Reboot- Board level Reset
2709a40c0fbSSheetal Tigadoli * 2-> Reset - SoC level Reset
2719a40c0fbSSheetal Tigadoli *
2729a40c0fbSSheetal Tigadoli * Spec allocates 8 bits, 2 nibble, for this. One nibble is sufficient
2739a40c0fbSSheetal Tigadoli * for sending the state hence We are utilizing 2nd nibble for vendor
2749a40c0fbSSheetal Tigadoli * define reset type.
2759a40c0fbSSheetal Tigadoli */
2769a40c0fbSSheetal Tigadoli scpi_sys_power_state((reset_type << VENDOR_RST_TYPE_SHIFT) |
2779a40c0fbSSheetal Tigadoli scpi_system_reboot);
2789a40c0fbSSheetal Tigadoli
2799a40c0fbSSheetal Tigadoli wfi();
2809a40c0fbSSheetal Tigadoli ERROR("BRCM System Reset: operation not handled.\n");
2819a40c0fbSSheetal Tigadoli panic();
2829a40c0fbSSheetal Tigadoli }
2839a40c0fbSSheetal Tigadoli
brcm_system_reset(void)2849a40c0fbSSheetal Tigadoli static void __dead2 brcm_system_reset(void)
2859a40c0fbSSheetal Tigadoli {
2863942d3a8SSheetal Tigadoli unsigned int reset_type;
2873942d3a8SSheetal Tigadoli
2883942d3a8SSheetal Tigadoli if (bcm_chimp_is_nic_mode())
2893942d3a8SSheetal Tigadoli reset_type = SOFT_RESET_L3;
2903942d3a8SSheetal Tigadoli else
2913942d3a8SSheetal Tigadoli reset_type = SOFT_SYS_RESET_L1;
2923942d3a8SSheetal Tigadoli
2933942d3a8SSheetal Tigadoli brcm_scp_sys_reset(reset_type);
2949a40c0fbSSheetal Tigadoli }
2959a40c0fbSSheetal Tigadoli
brcm_system_reset2(int is_vendor,int reset_type,u_register_t cookie)2969a40c0fbSSheetal Tigadoli static int brcm_system_reset2(int is_vendor, int reset_type,
2979a40c0fbSSheetal Tigadoli u_register_t cookie)
2989a40c0fbSSheetal Tigadoli {
2999a40c0fbSSheetal Tigadoli if (!is_vendor) {
3009a40c0fbSSheetal Tigadoli /* Architectural warm boot: only warm reset is supported */
3019a40c0fbSSheetal Tigadoli reset_type = SOFT_RESET_L3;
3023942d3a8SSheetal Tigadoli } else {
3033942d3a8SSheetal Tigadoli uint32_t boot_source = (uint32_t)cookie;
3043942d3a8SSheetal Tigadoli
3053942d3a8SSheetal Tigadoli boot_source &= BOOT_SOURCE_MASK;
3063942d3a8SSheetal Tigadoli brcm_stingray_set_straps(boot_source);
3079a40c0fbSSheetal Tigadoli }
3089a40c0fbSSheetal Tigadoli brcm_scp_sys_reset(reset_type);
3099a40c0fbSSheetal Tigadoli
3109a40c0fbSSheetal Tigadoli /*
3119a40c0fbSSheetal Tigadoli * brcm_scp_sys_reset cannot return (it is a __dead function),
3129a40c0fbSSheetal Tigadoli * but brcm_system_reset2 has to return some value, even in
3139a40c0fbSSheetal Tigadoli * this case.
3149a40c0fbSSheetal Tigadoli */
3159a40c0fbSSheetal Tigadoli return 0;
3169a40c0fbSSheetal Tigadoli }
3179a40c0fbSSheetal Tigadoli
brcm_validate_ns_entrypoint(uintptr_t entrypoint)3189a40c0fbSSheetal Tigadoli static int brcm_validate_ns_entrypoint(uintptr_t entrypoint)
3199a40c0fbSSheetal Tigadoli {
3209a40c0fbSSheetal Tigadoli /*
3219a40c0fbSSheetal Tigadoli * Check if the non secure entrypoint lies within the non
3229a40c0fbSSheetal Tigadoli * secure DRAM.
3239a40c0fbSSheetal Tigadoli */
3249a40c0fbSSheetal Tigadoli if ((entrypoint >= BRCM_NS_DRAM1_BASE) &&
3259a40c0fbSSheetal Tigadoli (entrypoint < (BRCM_NS_DRAM1_BASE + BRCM_NS_DRAM1_SIZE)))
3269a40c0fbSSheetal Tigadoli return PSCI_E_SUCCESS;
3270e16177eSManish V Badarkhe #ifdef __aarch64__
3289a40c0fbSSheetal Tigadoli if ((entrypoint >= BRCM_DRAM2_BASE) &&
3299a40c0fbSSheetal Tigadoli (entrypoint < (BRCM_DRAM2_BASE + BRCM_DRAM2_SIZE)))
3309a40c0fbSSheetal Tigadoli return PSCI_E_SUCCESS;
3319a40c0fbSSheetal Tigadoli
3329a40c0fbSSheetal Tigadoli if ((entrypoint >= BRCM_DRAM3_BASE) &&
3339a40c0fbSSheetal Tigadoli (entrypoint < (BRCM_DRAM3_BASE + BRCM_DRAM3_SIZE)))
3349a40c0fbSSheetal Tigadoli return PSCI_E_SUCCESS;
3359a40c0fbSSheetal Tigadoli #endif
3369a40c0fbSSheetal Tigadoli
3379a40c0fbSSheetal Tigadoli return PSCI_E_INVALID_ADDRESS;
3389a40c0fbSSheetal Tigadoli }
3399a40c0fbSSheetal Tigadoli
3409a40c0fbSSheetal Tigadoli /*******************************************************************************
3419a40c0fbSSheetal Tigadoli * ARM standard platform handler called to check the validity of the power state
3429a40c0fbSSheetal Tigadoli * parameter.
3439a40c0fbSSheetal Tigadoli ******************************************************************************/
brcm_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)3449a40c0fbSSheetal Tigadoli static int brcm_validate_power_state(unsigned int power_state,
3459a40c0fbSSheetal Tigadoli psci_power_state_t *req_state)
3469a40c0fbSSheetal Tigadoli {
3479a40c0fbSSheetal Tigadoli int pstate = psci_get_pstate_type(power_state);
3489a40c0fbSSheetal Tigadoli int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
3499a40c0fbSSheetal Tigadoli int i;
3509a40c0fbSSheetal Tigadoli
3519a40c0fbSSheetal Tigadoli assert(req_state);
3529a40c0fbSSheetal Tigadoli
3539a40c0fbSSheetal Tigadoli if (pwr_lvl > PLAT_MAX_PWR_LVL)
3549a40c0fbSSheetal Tigadoli return PSCI_E_INVALID_PARAMS;
3559a40c0fbSSheetal Tigadoli
3569a40c0fbSSheetal Tigadoli /* Sanity check the requested state */
3579a40c0fbSSheetal Tigadoli if (pstate == PSTATE_TYPE_STANDBY) {
3589a40c0fbSSheetal Tigadoli /*
3599a40c0fbSSheetal Tigadoli * It's possible to enter standby only on power level 0
3609a40c0fbSSheetal Tigadoli * Ignore any other power level.
3619a40c0fbSSheetal Tigadoli */
3629a40c0fbSSheetal Tigadoli if (pwr_lvl != MPIDR_AFFLVL0)
3639a40c0fbSSheetal Tigadoli return PSCI_E_INVALID_PARAMS;
3649a40c0fbSSheetal Tigadoli
3659a40c0fbSSheetal Tigadoli req_state->pwr_domain_state[MPIDR_AFFLVL0] =
3669a40c0fbSSheetal Tigadoli PLAT_LOCAL_STATE_RET;
3679a40c0fbSSheetal Tigadoli } else {
3689a40c0fbSSheetal Tigadoli for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
3699a40c0fbSSheetal Tigadoli req_state->pwr_domain_state[i] =
3709a40c0fbSSheetal Tigadoli PLAT_LOCAL_STATE_OFF;
3719a40c0fbSSheetal Tigadoli }
3729a40c0fbSSheetal Tigadoli
3739a40c0fbSSheetal Tigadoli /*
3749a40c0fbSSheetal Tigadoli * We expect the 'state id' to be zero.
3759a40c0fbSSheetal Tigadoli */
3769a40c0fbSSheetal Tigadoli if (psci_get_pstate_id(power_state))
3779a40c0fbSSheetal Tigadoli return PSCI_E_INVALID_PARAMS;
3789a40c0fbSSheetal Tigadoli
3799a40c0fbSSheetal Tigadoli return PSCI_E_SUCCESS;
3809a40c0fbSSheetal Tigadoli }
3819a40c0fbSSheetal Tigadoli
3829a40c0fbSSheetal Tigadoli /*******************************************************************************
3839a40c0fbSSheetal Tigadoli * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard
3849a40c0fbSSheetal Tigadoli * platform will take care of registering the handlers with PSCI.
3859a40c0fbSSheetal Tigadoli ******************************************************************************/
3869a40c0fbSSheetal Tigadoli plat_psci_ops_t plat_brcm_psci_pm_ops = {
3879a40c0fbSSheetal Tigadoli .pwr_domain_on = brcm_pwr_domain_on,
3889a40c0fbSSheetal Tigadoli .pwr_domain_on_finish = brcm_pwr_domain_on_finish,
3899a40c0fbSSheetal Tigadoli .pwr_domain_off = brcm_pwr_domain_off,
3909a40c0fbSSheetal Tigadoli .cpu_standby = brcm_cpu_standby,
3919a40c0fbSSheetal Tigadoli .system_off = brcm_scp_sys_shutdown,
3929a40c0fbSSheetal Tigadoli .system_reset = brcm_system_reset,
3939a40c0fbSSheetal Tigadoli .system_reset2 = brcm_system_reset2,
3949a40c0fbSSheetal Tigadoli .validate_ns_entrypoint = brcm_validate_ns_entrypoint,
3959a40c0fbSSheetal Tigadoli .validate_power_state = brcm_validate_power_state,
3969a40c0fbSSheetal Tigadoli };
3979a40c0fbSSheetal Tigadoli
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)3989a40c0fbSSheetal Tigadoli int plat_setup_psci_ops(uintptr_t sec_entrypoint,
3999a40c0fbSSheetal Tigadoli const struct plat_psci_ops **psci_ops)
4009a40c0fbSSheetal Tigadoli {
4019a40c0fbSSheetal Tigadoli *psci_ops = &plat_brcm_psci_pm_ops;
4029a40c0fbSSheetal Tigadoli
4039a40c0fbSSheetal Tigadoli /* Setup mailbox with entry point. */
4049a40c0fbSSheetal Tigadoli mmio_write_64(CRMU_CFG_BASE + offsetof(M0CFG, core_cfg.rvbar),
4059a40c0fbSSheetal Tigadoli sec_entrypoint);
4069a40c0fbSSheetal Tigadoli
4079a40c0fbSSheetal Tigadoli return 0;
4089a40c0fbSSheetal Tigadoli }
409