123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /*
- * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <errno.h>
- #include <platform_def.h>
- #include <arch_helpers.h>
- #include <common/debug.h>
- #include <drivers/delay_timer.h>
- #include <drivers/generic_delay_timer.h>
- #include <lib/cassert.h>
- #include <lib/psci/psci.h>
- #include <sq_common.h>
- #include "sq_scpi.h"
- uintptr_t sq_sec_entrypoint;
- int sq_pwr_domain_on(u_register_t mpidr)
- {
- #if SQ_USE_SCMI_DRIVER
- sq_scmi_on(mpidr);
- #else
- /*
- * SCP takes care of powering up parent power domains so we
- * only need to care about level 0
- */
- scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
- scpi_power_on);
- #endif
- return PSCI_E_SUCCESS;
- }
- static void sq_pwr_domain_on_finisher_common(
- const psci_power_state_t *target_state)
- {
- assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
- /*
- * Perform the common cluster specific operations i.e enable coherency
- * if this cluster was off.
- */
- if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
- plat_sq_interconnect_enter_coherency();
- }
- void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
- {
- /* Assert that the system power domain need not be initialized */
- assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
- sq_pwr_domain_on_finisher_common(target_state);
- /* Program the gic per-cpu distributor or re-distributor interface */
- sq_gic_pcpu_init();
- /* Enable the gic cpu interface */
- sq_gic_cpuif_enable();
- }
- #if !SQ_USE_SCMI_DRIVER
- static void sq_power_down_common(const psci_power_state_t *target_state)
- {
- uint32_t cluster_state = scpi_power_on;
- uint32_t system_state = scpi_power_on;
- /* Prevent interrupts from spuriously waking up this cpu */
- sq_gic_cpuif_disable();
- /* Check if power down at system power domain level is requested */
- if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
- system_state = scpi_power_retention;
- /* Cluster is to be turned off, so disable coherency */
- if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
- plat_sq_interconnect_exit_coherency();
- cluster_state = scpi_power_off;
- }
- /*
- * Ask the SCP to power down the appropriate components depending upon
- * their state.
- */
- scpi_set_sq_power_state(read_mpidr_el1(),
- scpi_power_off,
- cluster_state,
- system_state);
- }
- #endif
- void sq_pwr_domain_off(const psci_power_state_t *target_state)
- {
- #if SQ_USE_SCMI_DRIVER
- /* Prevent interrupts from spuriously waking up this cpu */
- sq_gic_cpuif_disable();
- /* Cluster is to be turned off, so disable coherency */
- if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
- plat_sq_interconnect_exit_coherency();
- }
- sq_scmi_off(target_state);
- #else
- sq_power_down_common(target_state);
- #endif
- }
- void __dead2 sq_system_off(void)
- {
- #if SQ_USE_SCMI_DRIVER
- sq_scmi_sys_shutdown();
- #else
- volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
- /* set PD[9] high to power off the system */
- gpio[5] |= 0x2; /* set output */
- gpio[1] |= 0x2; /* set high */
- dmbst();
- generic_delay_timer_init();
- mdelay(1);
- while (1) {
- gpio[1] &= ~0x2; /* set low */
- dmbst();
- mdelay(1);
- gpio[1] |= 0x2; /* set high */
- dmbst();
- mdelay(100);
- }
- wfi();
- ERROR("SQ System Off: operation not handled.\n");
- panic();
- #endif
- }
- void __dead2 sq_system_reset(void)
- {
- #if SQ_USE_SCMI_DRIVER
- sq_scmi_sys_reboot();
- #else
- uint32_t response;
- /* Send the system reset request to the SCP */
- response = scpi_sys_power_state(scpi_system_reboot);
- if (response != SCP_OK) {
- ERROR("SQ System Reset: SCP error %u.\n", response);
- panic();
- }
- wfi();
- ERROR("SQ System Reset: operation not handled.\n");
- panic();
- #endif
- }
- void sq_cpu_standby(plat_local_state_t cpu_state)
- {
- u_register_t scr;
- assert(cpu_state == SQ_LOCAL_STATE_RET);
- scr = read_scr_el3();
- /* Enable PhysicalIRQ bit for NS world to wake the CPU */
- write_scr_el3(scr | SCR_IRQ_BIT);
- isb();
- dsb();
- wfi();
- /*
- * Restore SCR to the original value, synchronisation of scr_el3 is
- * done by eret while el3_exit to save some execution cycles.
- */
- write_scr_el3(scr);
- }
- const plat_psci_ops_t sq_psci_ops = {
- .pwr_domain_on = sq_pwr_domain_on,
- .pwr_domain_off = sq_pwr_domain_off,
- .pwr_domain_on_finish = sq_pwr_domain_on_finish,
- .cpu_standby = sq_cpu_standby,
- .system_off = sq_system_off,
- .system_reset = sq_system_reset,
- };
- int plat_setup_psci_ops(uintptr_t sec_entrypoint,
- const struct plat_psci_ops **psci_ops)
- {
- #if !RESET_TO_BL31
- uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
- *sq_sec_ep = sec_entrypoint;
- flush_dcache_range((uint64_t)sq_sec_ep,
- sizeof(*sq_sec_ep));
- #else
- sq_sec_entrypoint = sec_entrypoint;
- flush_dcache_range((uint64_t)&sq_sec_entrypoint,
- sizeof(sq_sec_entrypoint));
- #endif
- *psci_ops = &sq_psci_ops;
- return 0;
- }
|