123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <arch_helpers.h>
- #include <common/debug.h>
- #include <drivers/arm/cci.h>
- #include <drivers/arm/gicv2.h>
- #include <drivers/arm/pl011.h>
- #include <drivers/arm/pl061_gpio.h>
- #include <drivers/delay_timer.h>
- #include <lib/mmio.h>
- #include <lib/psci/psci.h>
- #include <hi3660.h>
- #include <hi3660_crg.h>
- #include "drivers/pwrc/hisi_pwrc.h"
- #include "hikey960_def.h"
- #include "hikey960_private.h"
- #define CORE_PWR_STATE(state) \
- ((state)->pwr_domain_state[MPIDR_AFFLVL0])
- #define CLUSTER_PWR_STATE(state) \
- ((state)->pwr_domain_state[MPIDR_AFFLVL1])
- #define SYSTEM_PWR_STATE(state) \
- ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
- #define DMAC_GLB_REG_SEC 0x694
- #define AXI_CONF_BASE 0x820
- static unsigned int uart_base;
- static console_t console;
- static uintptr_t hikey960_sec_entrypoint;
- static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
- {
- unsigned long scr;
- scr = read_scr_el3();
- /* Enable Physical IRQ and FIQ to wake the CPU */
- write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
- /* Add barrier before CPU enter WFI state */
- isb();
- dsb();
- wfi();
- /*
- * Restore SCR to the original value, synchronisazion of
- * scr_el3 is done by eret while el3_exit to save some
- * execution cycles.
- */
- write_scr_el3(scr);
- }
- static int hikey960_pwr_domain_on(u_register_t mpidr)
- {
- unsigned int core = mpidr & MPIDR_CPU_MASK;
- unsigned int cluster =
- (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
- int cluster_stat = cluster_is_powered_on(cluster);
- hisi_set_cpu_boot_flag(cluster, core);
- mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
- hikey960_sec_entrypoint >> 2);
- if (cluster_stat)
- hisi_powerup_core(cluster, core);
- else
- hisi_powerup_cluster(cluster, core);
- return PSCI_E_SUCCESS;
- }
- static void
- hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
- {
- if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
- cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
- gicv2_pcpu_distif_init();
- gicv2_cpuif_enable();
- }
- void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
- {
- unsigned long mpidr = read_mpidr_el1();
- unsigned int core = mpidr & MPIDR_CPU_MASK;
- unsigned int cluster =
- (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
- clr_ex();
- isb();
- dsbsy();
- gicv2_cpuif_disable();
- hisi_clear_cpu_boot_flag(cluster, core);
- hisi_powerdn_core(cluster, core);
- /* check if any core is powered up */
- if (hisi_test_cpu_down(cluster, core)) {
- cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
- isb();
- dsbsy();
- hisi_powerdn_cluster(cluster, core);
- }
- }
- static void __dead2 hikey960_system_off(void)
- {
- gpio_set_direction(176, GPIO_DIR_OUT);
- gpio_set_value(176, GPIO_LEVEL_LOW);
- panic();
- }
- static void __dead2 hikey960_system_reset(void)
- {
- dsb();
- isb();
- mdelay(2000);
- mmio_write_32(SCTRL_SCPEREN1_REG,
- SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
- mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
- panic();
- }
- int hikey960_validate_power_state(unsigned int power_state,
- psci_power_state_t *req_state)
- {
- unsigned int pstate = psci_get_pstate_type(power_state);
- unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
- int i;
- assert(req_state);
- if (pwr_lvl > PLAT_MAX_PWR_LVL)
- return PSCI_E_INVALID_PARAMS;
- /* Sanity check the requested state */
- if (pstate == PSTATE_TYPE_STANDBY) {
- /*
- * It's possible to enter standby only on power level 0
- * Ignore any other power level.
- */
- if (pwr_lvl != MPIDR_AFFLVL0)
- return PSCI_E_INVALID_PARAMS;
- req_state->pwr_domain_state[MPIDR_AFFLVL0] =
- PLAT_MAX_RET_STATE;
- } else {
- for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
- req_state->pwr_domain_state[i] =
- PLAT_MAX_OFF_STATE;
- }
- /*
- * We expect the 'state id' to be zero.
- */
- if (psci_get_pstate_id(power_state))
- return PSCI_E_INVALID_PARAMS;
- return PSCI_E_SUCCESS;
- }
- static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
- {
- /*
- * Check if the non secure entrypoint lies within the non
- * secure DRAM.
- */
- if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
- return PSCI_E_SUCCESS;
- return PSCI_E_INVALID_ADDRESS;
- }
- static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
- {
- u_register_t mpidr = read_mpidr_el1();
- unsigned int core = mpidr & MPIDR_CPU_MASK;
- unsigned int cluster =
- (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
- if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
- return;
- if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
- clr_ex();
- isb();
- dsbsy();
- gicv2_cpuif_disable();
- hisi_cpuidle_lock(cluster, core);
- hisi_set_cpuidle_flag(cluster, core);
- hisi_cpuidle_unlock(cluster, core);
- mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
- hikey960_sec_entrypoint >> 2);
- hisi_enter_core_idle(cluster, core);
- }
- /* Perform the common cluster specific operations */
- if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
- hisi_cpuidle_lock(cluster, core);
- hisi_disable_pdc(cluster);
- /* check if any core is powered up */
- if (hisi_test_pwrdn_allcores(cluster, core)) {
- cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
- isb();
- dsbsy();
- /* mask the pdc wakeup irq, then
- * enable pdc to power down the core
- */
- hisi_pdc_mask_cluster_wakeirq(cluster);
- hisi_enable_pdc(cluster);
- hisi_cpuidle_unlock(cluster, core);
- /* check the SR flag bit to determine
- * CLUSTER_IDLE_IPC or AP_SR_IPC to send
- */
- if (hisi_test_ap_suspend_flag())
- hisi_enter_ap_suspend(cluster, core);
- else
- hisi_enter_cluster_idle(cluster, core);
- } else {
- /* enable pdc */
- hisi_enable_pdc(cluster);
- hisi_cpuidle_unlock(cluster, core);
- }
- }
- }
- static void hikey960_sr_dma_reinit(void)
- {
- unsigned int ctr = 0;
- mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
- /* 1~15 channel is set non_secure */
- for (ctr = 1; ctr <= 15; ctr++)
- mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
- (1 << 6) | (1 << 18));
- }
- static void
- hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
- {
- unsigned long mpidr = read_mpidr_el1();
- unsigned int core = mpidr & MPIDR_CPU_MASK;
- unsigned int cluster =
- (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
- /* Nothing to be done on waking up from retention from CPU level */
- if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
- return;
- hisi_cpuidle_lock(cluster, core);
- hisi_clear_cpuidle_flag(cluster, core);
- hisi_cpuidle_unlock(cluster, core);
- if (hisi_test_ap_suspend_flag()) {
- hikey960_sr_dma_reinit();
- gicv2_cpuif_enable();
- console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
- PL011_BAUDRATE, &console);
- }
- hikey960_pwr_domain_on_finish(target_state);
- }
- static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
- {
- int i;
- for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
- req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
- }
- static const plat_psci_ops_t hikey960_psci_ops = {
- .cpu_standby = hikey960_pwr_domain_standby,
- .pwr_domain_on = hikey960_pwr_domain_on,
- .pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
- .pwr_domain_off = hikey960_pwr_domain_off,
- .pwr_domain_suspend = hikey960_pwr_domain_suspend,
- .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
- .system_off = hikey960_system_off,
- .system_reset = hikey960_system_reset,
- .validate_power_state = hikey960_validate_power_state,
- .validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
- .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
- };
- int plat_setup_psci_ops(uintptr_t sec_entrypoint,
- const plat_psci_ops_t **psci_ops)
- {
- unsigned int id = 0;
- int ret;
- ret = hikey960_read_boardid(&id);
- if (ret == 0) {
- if (id == 5300U)
- uart_base = PL011_UART5_BASE;
- else
- uart_base = PL011_UART6_BASE;
- } else {
- uart_base = PL011_UART6_BASE;
- }
- hikey960_sec_entrypoint = sec_entrypoint;
- INFO("%s: sec_entrypoint=0x%lx\n", __func__,
- (unsigned long)hikey960_sec_entrypoint);
- /*
- * Initialize PSCI ops struct
- */
- *psci_ops = &hikey960_psci_ops;
- return 0;
- }
|