Browse Source

synquacer: Enable PSCI framework

PSCI framework uses SCPI driver to communicate to SCP firmware for
various power management operations. Following PSCI operations are
supported:
- CPU ON
- CPU OFF
- CPU STANDBY
- SYSTEM RESET
- SYSTEM OFF

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
pull/1427/head
Sumit Garg 6 years ago
parent
commit
753701ccb0
  1. 10
      plat/socionext/synquacer/include/platform_def.h
  2. 188
      plat/socionext/synquacer/sq_psci.c

10
plat/socionext/synquacer/include/platform_def.h

@ -15,6 +15,14 @@
#define PLATFORM_CORE_COUNT (PLAT_CLUSTER_COUNT * \
PLAT_MAX_CORES_PER_CLUSTER)
#define PLAT_MAX_PWR_LVL 1
#define PLAT_MAX_RET_STATE 1
#define PLAT_MAX_OFF_STATE 2
#define SQ_LOCAL_STATE_RUN 0
#define SQ_LOCAL_STATE_RET 1
#define SQ_LOCAL_STATE_OFF 2
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
@ -68,4 +76,6 @@
#define PLAT_SQ_GICD_BASE 0x30000000
#define PLAT_SQ_GICR_BASE 0x30400000
#define PLAT_SQ_GPIO_BASE 0x51000000
#endif /* __PLATFORM_DEF_H__ */

188
plat/socionext/synquacer/sq_psci.c

@ -0,0 +1,188 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <cassert.h>
#include <debug.h>
#include <delay_timer.h>
#include <errno.h>
#include <generic_delay_timer.h>
#include <platform_def.h>
#include <sq_common.h>
#include "sq_scpi.h"
#include <psci.h>
/* Macros to read the SQ power domain state */
#define SQ_PWR_LVL0 MPIDR_AFFLVL0
#define SQ_PWR_LVL1 MPIDR_AFFLVL1
#define SQ_PWR_LVL2 MPIDR_AFFLVL2
#define SQ_CORE_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL0]
#define SQ_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL1]
#define SQ_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > SQ_PWR_LVL1) ?\
(state)->pwr_domain_state[SQ_PWR_LVL2] : 0)
uintptr_t sq_sec_entrypoint;
int sq_pwr_domain_on(u_register_t mpidr)
{
/*
* 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);
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();
}
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);
}
void sq_pwr_domain_off(const psci_power_state_t *target_state)
{
sq_power_down_common(target_state);
}
void __dead2 sq_system_off(void)
{
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();
}
void __dead2 sq_system_reset(void)
{
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();
}
void sq_cpu_standby(plat_local_state_t cpu_state)
{
unsigned int 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)
{
sq_sec_entrypoint = sec_entrypoint;
flush_dcache_range((uint64_t)&sq_sec_entrypoint,
sizeof(sq_sec_entrypoint));
*psci_ops = &sq_psci_ops;
return 0;
}
Loading…
Cancel
Save