903 lines
28 KiB
Diff
903 lines
28 KiB
Diff
From 67767123b31cfbb206e3eb2b7ca845794e025ffc Mon Sep 17 00:00:00 2001
|
|
From: Samuel Holland <samuel@sholland.org>
|
|
Date: Sun, 17 May 2020 19:12:27 -0500
|
|
Subject: [PATCH 3/5] allwinner: Remove legacy native power management
|
|
|
|
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
|
Change-Id: Id85732db352f811dd6d5e6064624bb4752bda0f3
|
|
---
|
|
plat/allwinner/common/allwinner-common.mk | 1 -
|
|
plat/allwinner/common/arisc_off.S | 115 -------------
|
|
plat/allwinner/common/include/sunxi_private.h | 7 -
|
|
plat/allwinner/common/sunxi_bl31_setup.c | 3 -
|
|
plat/allwinner/common/sunxi_common.c | 76 ---------
|
|
plat/allwinner/common/sunxi_cpu_ops.c | 123 --------------
|
|
plat/allwinner/common/sunxi_pm.c | 80 +++------
|
|
.../sun50i_a64/include/core_off_arisc.h | 39 -----
|
|
plat/allwinner/sun50i_a64/sunxi_power.c | 156 ++----------------
|
|
.../sun50i_h6/include/core_off_arisc.h | 39 -----
|
|
plat/allwinner/sun50i_h6/sunxi_power.c | 25 ---
|
|
11 files changed, 40 insertions(+), 624 deletions(-)
|
|
delete mode 100644 plat/allwinner/common/arisc_off.S
|
|
delete mode 100644 plat/allwinner/common/sunxi_cpu_ops.c
|
|
delete mode 100644 plat/allwinner/sun50i_a64/include/core_off_arisc.h
|
|
delete mode 100644 plat/allwinner/sun50i_h6/include/core_off_arisc.h
|
|
|
|
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
|
|
index e60ebc6f2..617eb6de2 100644
|
|
--- a/plat/allwinner/common/allwinner-common.mk
|
|
+++ b/plat/allwinner/common/allwinner-common.mk
|
|
@@ -31,7 +31,6 @@ BL31_SOURCES += drivers/allwinner/axp/common.c \
|
|
plat/common/plat_gicv2.c \
|
|
plat/common/plat_psci_common.c \
|
|
${AW_PLAT}/common/sunxi_bl31_setup.c \
|
|
- ${AW_PLAT}/common/sunxi_cpu_ops.c \
|
|
${AW_PLAT}/common/sunxi_pm.c \
|
|
${AW_PLAT}/${PLAT}/sunxi_power.c \
|
|
${AW_PLAT}/common/sunxi_security.c \
|
|
diff --git a/plat/allwinner/common/arisc_off.S b/plat/allwinner/common/arisc_off.S
|
|
deleted file mode 100644
|
|
index ed10832c9..000000000
|
|
--- a/plat/allwinner/common/arisc_off.S
|
|
+++ /dev/null
|
|
@@ -1,115 +0,0 @@
|
|
-# turn_off_core.S
|
|
-#
|
|
-# Copyright (c) 2018, Andre Przywara <osp@andrep.de>
|
|
-# SPDX-License-Identifier: BSD-3-Clause
|
|
-#
|
|
-# OpenRISC assembly to turn off an ARM core on an Allwinner SoC from
|
|
-# the arisc management controller.
|
|
-# Generate a binary representation with:
|
|
-# $ or1k-elf-as -c -o turn_off_core.o turn_off_core.S
|
|
-# $ or1k-elf-objcopy -O binary --reverse-bytes=4 turn_off_core.o \
|
|
-# turn_off_core.bin
|
|
-# The encoded instructions go into an array defined in
|
|
-# plat/allwinner/sun50i_*/include/core_off_arisc.h, to be handed off to
|
|
-# the arisc processor.
|
|
-#
|
|
-# This routine is meant to be called directly from arisc reset (put the
|
|
-# start address in the reset vector), to be actually triggered by that
|
|
-# very ARM core to be turned off.
|
|
-# It expects the core number presented as a mask in the upper half of
|
|
-# r3, so to be patched in the lower 16 bits of the first instruction,
|
|
-# overwriting the 0 in this code here.
|
|
-# The code will do the following:
|
|
-# - Read the C_CPU_STATUS register, which contains the status of the WFI
|
|
-# lines of each of the four A53 cores.
|
|
-# - Loop until the core in question reaches WFI.
|
|
-# - Using that mask, activate the core output clamps by setting the
|
|
-# respective core bit in CPUX_PWROFF_GATING_REG (0x1f01500).
|
|
-# Note that the clamp for core 0 covers more than just the core, activating
|
|
-# it hangs the whole system. So we skip this step for core 0.
|
|
-# - Using the negated mask, assert the core's reset line by clearing the
|
|
-# respective bit in C_RST_CTRL (0x1f01c30).
|
|
-# - Finally turn off the core's power switch by writing 0xff to the
|
|
-# respective CPUx_PWR_SWITCH_REG (0x1f01540 ff.)
|
|
-# - Assert the arisc's own reset to end execution.
|
|
-# This also signals other arisc users that the chip is free again.
|
|
-# So in C this would look like:
|
|
-# while (!(readl(0x1700030) & (1U << core_nr)))
|
|
-# ;
|
|
-# if (core_nr != 0)
|
|
-# writel(readl(0x1f01500) | (1U << core_nr), 0x1f01500);
|
|
-# writel(readl(0x1f01c30) & ~(1U << core_nr), 0x1f01c30);
|
|
-# writel(0xff, 0x1f01540 + (core_nr * 4));
|
|
-# (using A64/H5 addresses)
|
|
-
|
|
-.text
|
|
-_start:
|
|
- l.movhi r3, 0 # FIXUP! with core mask
|
|
- l.movhi r0, 0 # clear r0
|
|
- l.movhi r13, 0x170 # r13: CPU_CFG_BASE=0x01700000
|
|
-wait_wfi:
|
|
- l.lwz r5, 0x30(r13) # load C_CPU_STATUS
|
|
- l.and r5, r5, r3 # mask requested core
|
|
- l.sfeq r5, r0 # is it not yet in WFI?
|
|
- l.bf wait_wfi # try again
|
|
-
|
|
- l.srli r6, r3, 16 # move mask to lower 16 bits
|
|
- l.sfeqi r6, 1 # core 0 is special
|
|
- l.bf 1f # don't touch the bit for core 0
|
|
- l.movhi r13, 0x1f0 # address of R_CPUCFG (delay)
|
|
- l.lwz r5, 0x1500(r13) # core output clamps
|
|
- l.or r5, r5, r6 # set bit to ...
|
|
- l.sw 0x1500(r13), r5 # ... activate for our core
|
|
-
|
|
-1: l.lwz r5, 0x1c30(r13) # CPU power-on reset
|
|
- l.xori r6, r6, -1 # negate core mask
|
|
- l.and r5, r5, r6 # clear bit to ...
|
|
- l.sw 0x1c30(r13), r5 # ... assert for our core
|
|
-
|
|
- l.ff1 r6, r3 # get core number from high mask
|
|
- l.addi r6, r6, -17 # convert to 0-3
|
|
- l.slli r6, r6, 2 # r5: core number*4 (0-12)
|
|
- l.add r6, r6, r13 # add to base address
|
|
- l.ori r5, r0, 0xff # 0xff means all switches off
|
|
- l.sw 0x1540(r6), r5 # core power switch registers
|
|
-
|
|
-reset: l.sw 0x1c00(r13),r0 # pull down our own reset line
|
|
-
|
|
- l.j reset # just in case ....
|
|
- l.nop 0x0 # (delay slot)
|
|
-
|
|
-# same as above, but with the MMIO addresses matching the H6 SoC
|
|
-_start_h6:
|
|
- l.movhi r3, 0 # FIXUP! with core mask
|
|
- l.movhi r0, 0 # clear r0
|
|
- l.movhi r13, 0x901 # r13: CPU_CFG_BASE=0x09010000
|
|
-1:
|
|
- l.lwz r5, 0x80(r13) # load C_CPU_STATUS
|
|
- l.and r5, r5, r3 # mask requested core
|
|
- l.sfeq r5, r0 # is it not yet in WFI?
|
|
- l.bf 1b # try again
|
|
-
|
|
- l.srli r6, r3, 16 # move mask to lower 16 bits(ds)
|
|
- l.sfeqi r6, 1 # core 0 is special
|
|
- l.bf 1f # don't touch the bit for core 0
|
|
- l.movhi r13, 0x700 # address of R_CPUCFG (ds)
|
|
- l.lwz r5, 0x0444(r13) # core output clamps
|
|
- l.or r5, r5, r6 # set bit to ...
|
|
- l.sw 0x0444(r13), r5 # ... activate for our core
|
|
-
|
|
-1: l.lwz r5, 0x0440(r13) # CPU power-on reset
|
|
- l.xori r6, r6, -1 # negate core mask
|
|
- l.and r5, r5, r6 # clear bit to ...
|
|
- l.sw 0x0440(r13), r5 # ... assert for our core
|
|
-
|
|
- l.ff1 r6, r3 # get core number from high mask
|
|
- l.addi r6, r6, -17 # convert to 0-3
|
|
- l.slli r6, r6, 2 # r5: core number*4 (0-12)
|
|
- l.add r6, r6, r13 # add to base address
|
|
- l.ori r5, r0, 0xff # 0xff means all switches off
|
|
- l.sw 0x0450(r6), r5 # core power switch registers
|
|
-
|
|
-1: l.sw 0x0400(r13),r0 # pull down our own reset line
|
|
-
|
|
- l.j 1b # just in case ...
|
|
- l.nop 0x0 # (delay slot)
|
|
diff --git a/plat/allwinner/common/include/sunxi_private.h b/plat/allwinner/common/include/sunxi_private.h
|
|
index dcf3dc965..7b6cff07c 100644
|
|
--- a/plat/allwinner/common/include/sunxi_private.h
|
|
+++ b/plat/allwinner/common/include/sunxi_private.h
|
|
@@ -9,17 +9,10 @@
|
|
|
|
void sunxi_configure_mmu_el3(int flags);
|
|
|
|
-void sunxi_cpu_on(u_register_t mpidr);
|
|
-void sunxi_cpu_off(u_register_t mpidr);
|
|
-void sunxi_disable_secondary_cpus(u_register_t primary_mpidr);
|
|
-void sunxi_power_down(void);
|
|
-
|
|
int sunxi_pmic_setup(uint16_t socid, const void *fdt);
|
|
void sunxi_security_setup(void);
|
|
|
|
uint16_t sunxi_read_soc_id(void);
|
|
-void sunxi_set_gpio_out(char port, int pin, bool level_high);
|
|
int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb);
|
|
-void sunxi_execute_arisc_code(uint32_t *code, size_t size, uint16_t param);
|
|
|
|
#endif /* SUNXI_PRIVATE_H */
|
|
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
|
|
index e836a345b..fe511d02c 100644
|
|
--- a/plat/allwinner/common/sunxi_bl31_setup.c
|
|
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
|
|
@@ -100,9 +100,6 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|
bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
|
|
DISABLE_ALL_EXCEPTIONS);
|
|
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
|
|
-
|
|
- /* Turn off all secondary CPUs */
|
|
- sunxi_disable_secondary_cpus(read_mpidr());
|
|
}
|
|
|
|
void bl31_plat_arch_setup(void)
|
|
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
|
|
index 0ca18adc3..61826c6af 100644
|
|
--- a/plat/allwinner/common/sunxi_common.c
|
|
+++ b/plat/allwinner/common/sunxi_common.c
|
|
@@ -82,35 +82,6 @@ uint16_t sunxi_read_soc_id(void)
|
|
return reg >> 16;
|
|
}
|
|
|
|
-/*
|
|
- * Configure a given pin to the GPIO-OUT function and sets its level.
|
|
- * The port is given as a capital letter, the pin is the number within
|
|
- * this port group.
|
|
- * So to set pin PC7 to high, use: sunxi_set_gpio_out('C', 7, true);
|
|
- */
|
|
-void sunxi_set_gpio_out(char port, int pin, bool level_high)
|
|
-{
|
|
- uintptr_t port_base;
|
|
-
|
|
- if (port < 'A' || port > 'L')
|
|
- return;
|
|
- if (port == 'L')
|
|
- port_base = SUNXI_R_PIO_BASE;
|
|
- else
|
|
- port_base = SUNXI_PIO_BASE + (port - 'A') * 0x24;
|
|
-
|
|
- /* Set the new level first before configuring the pin. */
|
|
- if (level_high)
|
|
- mmio_setbits_32(port_base + 0x10, BIT(pin));
|
|
- else
|
|
- mmio_clrbits_32(port_base + 0x10, BIT(pin));
|
|
-
|
|
- /* configure pin as GPIO out (4(3) bits per pin, 1: GPIO out */
|
|
- mmio_clrsetbits_32(port_base + (pin / 8) * 4,
|
|
- 0x7 << ((pin % 8) * 4),
|
|
- 0x1 << ((pin % 8) * 4));
|
|
-}
|
|
-
|
|
int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|
{
|
|
uint32_t pin_func = 0x77;
|
|
@@ -165,50 +136,3 @@ int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
|
|
|
|
return 0;
|
|
}
|
|
-
|
|
-/* This lock synchronises access to the arisc management processor. */
|
|
-DEFINE_BAKERY_LOCK(arisc_lock);
|
|
-
|
|
-/*
|
|
- * Tell the "arisc" SCP core (an OpenRISC core) to execute some code.
|
|
- * We don't have any service running there, so we place some OpenRISC code
|
|
- * in SRAM, put the address of that into the reset vector and release the
|
|
- * arisc reset line. The SCP will execute that code and pull the line up again.
|
|
- */
|
|
-void sunxi_execute_arisc_code(uint32_t *code, size_t size, uint16_t param)
|
|
-{
|
|
- uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
|
|
-
|
|
- do {
|
|
- bakery_lock_get(&arisc_lock);
|
|
- /* Wait until the arisc is in reset state. */
|
|
- if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
|
|
- break;
|
|
-
|
|
- bakery_lock_release(&arisc_lock);
|
|
- } while (1);
|
|
-
|
|
- /* Patch up the code to feed in an input parameter. */
|
|
- code[0] = (code[0] & ~0xffff) | param;
|
|
- clean_dcache_range((uintptr_t)code, size);
|
|
-
|
|
- /*
|
|
- * The OpenRISC unconditional branch has opcode 0, the branch offset
|
|
- * is in the lower 26 bits, containing the distance to the target,
|
|
- * in instruction granularity (32 bits).
|
|
- */
|
|
- mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
|
|
- clean_dcache_range(arisc_reset_vec, 4);
|
|
-
|
|
- /* De-assert the arisc reset line to let it run. */
|
|
- mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
|
|
-
|
|
- /*
|
|
- * We release the lock here, although the arisc is still busy.
|
|
- * But as long as it runs, the reset line is high, so other users
|
|
- * won't leave the loop above.
|
|
- * Once it has finished, the code is supposed to clear the reset line,
|
|
- * to signal this to other users.
|
|
- */
|
|
- bakery_lock_release(&arisc_lock);
|
|
-}
|
|
diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c
|
|
deleted file mode 100644
|
|
index 6e29b69bf..000000000
|
|
--- a/plat/allwinner/common/sunxi_cpu_ops.c
|
|
+++ /dev/null
|
|
@@ -1,123 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <assert.h>
|
|
-
|
|
-#include <platform_def.h>
|
|
-
|
|
-#include <arch_helpers.h>
|
|
-#include <common/debug.h>
|
|
-#include <drivers/delay_timer.h>
|
|
-#include <lib/mmio.h>
|
|
-#include <lib/utils_def.h>
|
|
-#include <plat/common/platform.h>
|
|
-
|
|
-#include <core_off_arisc.h>
|
|
-#include <sunxi_cpucfg.h>
|
|
-#include <sunxi_mmap.h>
|
|
-#include <sunxi_private.h>
|
|
-
|
|
-static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
|
|
-{
|
|
- if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
|
|
- return;
|
|
-
|
|
- VERBOSE("PSCI: Disabling power to cluster %d core %d\n", cluster, core);
|
|
-
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff);
|
|
-}
|
|
-
|
|
-static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core)
|
|
-{
|
|
- if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0)
|
|
- return;
|
|
-
|
|
- VERBOSE("PSCI: Enabling power to cluster %d core %d\n", cluster, core);
|
|
-
|
|
- /* Power enable sequence from original Allwinner sources */
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe);
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8);
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0);
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80);
|
|
- mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00);
|
|
-}
|
|
-
|
|
-void sunxi_cpu_off(u_register_t mpidr)
|
|
-{
|
|
- unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
|
|
- unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
|
-
|
|
- VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
|
|
-
|
|
- /* Deassert DBGPWRDUP */
|
|
- mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
|
|
-
|
|
- /* We can't turn ourself off like this, but it works for other cores. */
|
|
- if (read_mpidr() != mpidr) {
|
|
- /* Activate the core output clamps, but not for core 0. */
|
|
- if (core != 0)
|
|
- mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster),
|
|
- BIT(core));
|
|
- /* Assert CPU power-on reset */
|
|
- mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
|
|
- /* Remove power from the CPU */
|
|
- sunxi_cpu_disable_power(cluster, core);
|
|
-
|
|
- return;
|
|
- }
|
|
-
|
|
- /* Simplifies assembly, all SoCs so far are single cluster anyway. */
|
|
- assert(cluster == 0);
|
|
-
|
|
- /*
|
|
- * If we are supposed to turn ourself off, tell the arisc SCP
|
|
- * to do that work for us. The code expects the core mask to be
|
|
- * patched into the first instruction.
|
|
- */
|
|
- sunxi_execute_arisc_code(arisc_core_off, sizeof(arisc_core_off),
|
|
- BIT_32(core));
|
|
-}
|
|
-
|
|
-void sunxi_cpu_on(u_register_t mpidr)
|
|
-{
|
|
- unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
|
|
- unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
|
|
-
|
|
- VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
|
|
-
|
|
- /* Assert CPU core reset */
|
|
- mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
|
|
- /* Assert CPU power-on reset */
|
|
- mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
|
|
- /* Set CPU to start in AArch64 mode */
|
|
- mmio_setbits_32(SUNXI_CPUCFG_CLS_CTRL_REG0(cluster), BIT(24 + core));
|
|
- /* Apply power to the CPU */
|
|
- sunxi_cpu_enable_power(cluster, core);
|
|
- /* Release the core output clamps */
|
|
- mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
|
|
- /* Deassert CPU power-on reset */
|
|
- mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
|
|
- /* Deassert CPU core reset */
|
|
- mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
|
|
- /* Assert DBGPWRDUP */
|
|
- mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
|
|
-}
|
|
-
|
|
-void sunxi_disable_secondary_cpus(u_register_t primary_mpidr)
|
|
-{
|
|
- unsigned int cluster;
|
|
- unsigned int core;
|
|
-
|
|
- for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
|
|
- for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
|
|
- u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
|
|
- (core << MPIDR_AFF0_SHIFT) |
|
|
- BIT(31);
|
|
- if (mpidr != primary_mpidr)
|
|
- sunxi_cpu_off(mpidr);
|
|
- }
|
|
- }
|
|
-}
|
|
diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c
|
|
index 17ef7bfda..9cb31bf15 100644
|
|
--- a/plat/allwinner/common/sunxi_pm.c
|
|
+++ b/plat/allwinner/common/sunxi_pm.c
|
|
@@ -53,8 +53,6 @@
|
|
*/
|
|
#define SCP_FIRMWARE_MAGIC 0xb4400012
|
|
|
|
-static bool scpi_available;
|
|
-
|
|
static inline scpi_power_state_t scpi_map_state(plat_local_state_t psci_state)
|
|
{
|
|
if (is_local_state_run(psci_state))
|
|
@@ -80,14 +78,10 @@ static int sunxi_pwr_domain_on(u_register_t mpidr)
|
|
if (mpidr_is_valid(mpidr) == 0)
|
|
return PSCI_E_INTERN_FAIL;
|
|
|
|
- if (scpi_available) {
|
|
- scpi_set_css_power_state(mpidr,
|
|
- scpi_power_on,
|
|
- scpi_power_on,
|
|
- scpi_power_on);
|
|
- } else {
|
|
- sunxi_cpu_on(mpidr);
|
|
- }
|
|
+ scpi_set_css_power_state(mpidr,
|
|
+ scpi_power_on,
|
|
+ scpi_power_on,
|
|
+ scpi_power_on);
|
|
|
|
return PSCI_E_SUCCESS;
|
|
}
|
|
@@ -101,20 +95,10 @@ static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
|
|
if (is_local_state_off(cpu_pwr_state))
|
|
gicv2_cpuif_disable();
|
|
|
|
- if (scpi_available) {
|
|
- scpi_set_css_power_state(read_mpidr(),
|
|
- scpi_map_state(cpu_pwr_state),
|
|
- scpi_map_state(cluster_pwr_state),
|
|
- scpi_map_state(system_pwr_state));
|
|
- }
|
|
-}
|
|
-
|
|
-static void __dead2 sunxi_pwr_down_wfi(const psci_power_state_t *target_state)
|
|
-{
|
|
- sunxi_cpu_off(read_mpidr());
|
|
-
|
|
- while (1)
|
|
- wfi();
|
|
+ scpi_set_css_power_state(read_mpidr(),
|
|
+ scpi_map_state(cpu_pwr_state),
|
|
+ scpi_map_state(cluster_pwr_state),
|
|
+ scpi_map_state(system_pwr_state));
|
|
}
|
|
|
|
static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
|
@@ -131,22 +115,12 @@ static void __dead2 sunxi_system_off(void)
|
|
{
|
|
gicv2_cpuif_disable();
|
|
|
|
- if (scpi_available) {
|
|
- /* Send the power down request to the SCP */
|
|
- uint32_t ret = scpi_sys_power_state(scpi_system_shutdown);
|
|
+ /* Send the power down request to the SCP */
|
|
+ uint32_t ret = scpi_sys_power_state(scpi_system_shutdown);
|
|
|
|
- if (ret == SCP_OK)
|
|
- wfi();
|
|
-
|
|
- ERROR("PSCI: SCPI %s failed: %d\n", "shutdown", ret);
|
|
- }
|
|
-
|
|
- /* Turn off all secondary CPUs */
|
|
- sunxi_disable_secondary_cpus(read_mpidr());
|
|
-
|
|
- sunxi_power_down();
|
|
+ if (ret == SCP_OK)
|
|
+ wfi();
|
|
|
|
- wfi();
|
|
ERROR("PSCI: Cannot turn off system, halting\n");
|
|
panic();
|
|
}
|
|
@@ -155,15 +129,11 @@ static void __dead2 sunxi_system_reset(void)
|
|
{
|
|
gicv2_cpuif_disable();
|
|
|
|
- if (scpi_available) {
|
|
- /* Send the system reset request to the SCP */
|
|
- uint32_t ret = scpi_sys_power_state(scpi_system_reboot);
|
|
-
|
|
- if (ret == SCP_OK)
|
|
- wfi();
|
|
+ /* Send the system reset request to the SCP */
|
|
+ uint32_t ret = scpi_sys_power_state(scpi_system_reboot);
|
|
|
|
- ERROR("PSCI: SCPI %s failed: %d\n", "reboot", ret);
|
|
- }
|
|
+ if (ret == SCP_OK)
|
|
+ wfi();
|
|
|
|
/* Reset the whole system when the watchdog times out */
|
|
mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
|
|
@@ -249,20 +219,26 @@ static int sunxi_get_node_hw_state(u_register_t mpidr,
|
|
return ((cpu_state & BIT(cpu)) != 0) ? HW_ON : HW_OFF;
|
|
}
|
|
|
|
-static plat_psci_ops_t sunxi_psci_ops = {
|
|
+static const plat_psci_ops_t sunxi_psci_ops = {
|
|
.cpu_standby = sunxi_cpu_standby,
|
|
.pwr_domain_on = sunxi_pwr_domain_on,
|
|
.pwr_domain_off = sunxi_pwr_domain_off,
|
|
+ .pwr_domain_suspend = sunxi_pwr_domain_off,
|
|
.pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
|
|
+ .pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish,
|
|
.system_off = sunxi_system_off,
|
|
.system_reset = sunxi_system_reset,
|
|
.validate_power_state = sunxi_validate_power_state,
|
|
.validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
|
|
+ .get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state,
|
|
+ .get_node_hw_state = sunxi_get_node_hw_state,
|
|
};
|
|
|
|
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
|
|
const plat_psci_ops_t **psci_ops)
|
|
{
|
|
+ bool scpi_available = false;
|
|
+
|
|
assert(psci_ops);
|
|
|
|
/* Program all CPU entry points. */
|
|
@@ -292,16 +268,6 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
|
|
|
|
NOTICE("PSCI: System suspend is %s\n",
|
|
scpi_available ? "available via SCPI" : "unavailable");
|
|
- if (scpi_available) {
|
|
- /* Suspend is only available via SCPI. */
|
|
- sunxi_psci_ops.pwr_domain_suspend = sunxi_pwr_domain_off;
|
|
- sunxi_psci_ops.pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish;
|
|
- sunxi_psci_ops.get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state;
|
|
- sunxi_psci_ops.get_node_hw_state = sunxi_get_node_hw_state;
|
|
- } else {
|
|
- /* This is only needed when SCPI is unavailable. */
|
|
- sunxi_psci_ops.pwr_domain_pwr_down_wfi = sunxi_pwr_down_wfi;
|
|
- }
|
|
|
|
*psci_ops = &sunxi_psci_ops;
|
|
|
|
diff --git a/plat/allwinner/sun50i_a64/include/core_off_arisc.h b/plat/allwinner/sun50i_a64/include/core_off_arisc.h
|
|
deleted file mode 100644
|
|
index ae436ca1b..000000000
|
|
--- a/plat/allwinner/sun50i_a64/include/core_off_arisc.h
|
|
+++ /dev/null
|
|
@@ -1,39 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-static uint32_t arisc_core_off[] = {
|
|
- 0x18600000, /* l.movhi r3, <corenr> */
|
|
- 0x18000000, /* l.movhi r0, 0x0 */
|
|
- 0x19a00170, /* l.movhi r13, 0x170 */
|
|
- 0x84ad0030, /* l.lwz r5, 0x30(r13) */
|
|
- 0xe0a51803, /* l.and r5, r5, r3 */
|
|
- 0xe4050000, /* l.sfeq r5, r0 */
|
|
- 0x13fffffd, /* l.bf -12 */
|
|
-
|
|
- 0xb8c30050, /* l.srli r6, r3, 16 */
|
|
- 0xbc060001, /* l.sfeqi r6, 1 */
|
|
- 0x10000005, /* l.bf +20 */
|
|
- 0x19a001f0, /* l.movhi r13, 0x1f0 */
|
|
- 0x84ad1500, /* l.lwz r5, 0x1500(r13) */
|
|
- 0xe0a53004, /* l.or r5, r5, r6 */
|
|
- 0xd44d2d00, /* l.sw 0x1500(r13), r5 */
|
|
-
|
|
- 0x84ad1c30, /* l.lwz r5, 0x1c30(r13) */
|
|
- 0xacc6ffff, /* l.xori r6, r6, -1 */
|
|
- 0xe0a53003, /* l.and r5, r5, r6 */
|
|
- 0xd46d2c30, /* l.sw 0x1c30(r13), r5 */
|
|
-
|
|
- 0xe0c3000f, /* l.ff1 r6, r3 */
|
|
- 0x9cc6ffef, /* l.addi r6, r6, -17 */
|
|
- 0xb8c60002, /* l.slli r6, r6, 2 */
|
|
- 0xe0c66800, /* l.add r6, r6, r13 */
|
|
- 0xa8a000ff, /* l.ori r5, r0, 0xff */
|
|
- 0xd4462d40, /* l.sw 0x1540(r6), r5 */
|
|
-
|
|
- 0xd46d0400, /* l.sw 0x1c00(r13), r0 */
|
|
- 0x03ffffff, /* l.j -1 */
|
|
- 0x15000000, /* l.nop */
|
|
-};
|
|
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
|
|
index 5b7d76ae9..d0b53d4e4 100644
|
|
--- a/plat/allwinner/sun50i_a64/sunxi_power.c
|
|
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
|
|
@@ -12,76 +12,22 @@
|
|
#include <common/debug.h>
|
|
#include <drivers/allwinner/axp.h>
|
|
#include <drivers/allwinner/sunxi_rsb.h>
|
|
-#include <lib/mmio.h>
|
|
|
|
#include <sunxi_def.h>
|
|
#include <sunxi_mmap.h>
|
|
#include <sunxi_private.h>
|
|
|
|
-static enum pmic_type {
|
|
- UNKNOWN,
|
|
- GENERIC_H5,
|
|
- GENERIC_A64,
|
|
- REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */
|
|
- AXP803_RSB, /* PMIC connected via RSB on most A64 boards */
|
|
-} pmic;
|
|
-
|
|
#define AXP803_HW_ADDR 0x3a3
|
|
#define AXP803_RT_ADDR 0x2d
|
|
|
|
-/*
|
|
- * On boards without a proper PMIC we struggle to turn off the system properly.
|
|
- * Try to turn off as much off the system as we can, to reduce power
|
|
- * consumption. This should be entered with only one core running and SMP
|
|
- * disabled.
|
|
- * This function only cares about peripherals.
|
|
- */
|
|
-static void sunxi_turn_off_soc(uint16_t socid)
|
|
+int axp_read(uint8_t reg)
|
|
{
|
|
- int i;
|
|
-
|
|
- /** Turn off most peripherals, most importantly DRAM users. **/
|
|
- /* Keep DRAM controller running for now. */
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
|
|
- /* Contains msgbox (bit 21) and spinlock (bit 22) */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
|
|
- /* Keep PIO controller running for now. */
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
|
|
- /* Contains UART0 (bit 16) */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
|
|
-
|
|
- /** Turn off DRAM controller. **/
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
|
|
-
|
|
- /** Migrate CPU and bus clocks away from the PLLs. **/
|
|
- /* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
|
|
- /* APB2: use OSC24M */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
|
|
- /* AHB2: use AHB1 clock */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
|
|
- /* CPU: use OSC24M */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
|
|
-
|
|
- /** Turn off PLLs. **/
|
|
- for (i = 0; i < 6; i++)
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
|
|
- switch (socid) {
|
|
- case SUNXI_SOC_H5:
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
|
|
- break;
|
|
- case SUNXI_SOC_A64:
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
|
|
- mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
|
|
- break;
|
|
- }
|
|
+ return rsb_read(AXP803_RT_ADDR, reg);
|
|
+}
|
|
+
|
|
+int axp_write(uint8_t reg, uint8_t val)
|
|
+{
|
|
+ return rsb_write(AXP803_RT_ADDR, reg, val);
|
|
}
|
|
|
|
static int rsb_init(void)
|
|
@@ -119,92 +65,24 @@ static int rsb_init(void)
|
|
return axp_check_id();
|
|
}
|
|
|
|
-int axp_read(uint8_t reg)
|
|
-{
|
|
- return rsb_read(AXP803_RT_ADDR, reg);
|
|
-}
|
|
-
|
|
-int axp_write(uint8_t reg, uint8_t val)
|
|
-{
|
|
- return rsb_write(AXP803_RT_ADDR, reg, val);
|
|
-}
|
|
-
|
|
int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
|
{
|
|
int ret;
|
|
|
|
- switch (socid) {
|
|
- case SUNXI_SOC_H5:
|
|
- NOTICE("PMIC: Assuming H5 reference regulator design\n");
|
|
-
|
|
- pmic = REF_DESIGN_H5;
|
|
+ if (socid != SUNXI_SOC_A64)
|
|
+ return 0;
|
|
|
|
- break;
|
|
- case SUNXI_SOC_A64:
|
|
- pmic = GENERIC_A64;
|
|
+ INFO("PMIC: Probing AXP803 on RSB\n");
|
|
|
|
- INFO("PMIC: Probing AXP803 on RSB\n");
|
|
-
|
|
- ret = sunxi_init_platform_r_twi(socid, true);
|
|
- if (ret)
|
|
- return ret;
|
|
+ ret = sunxi_init_platform_r_twi(socid, true);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- ret = rsb_init();
|
|
- if (ret)
|
|
- return ret;
|
|
+ ret = rsb_init();
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- pmic = AXP803_RSB;
|
|
- axp_setup_regulators(fdt);
|
|
+ axp_setup_regulators(fdt);
|
|
|
|
- break;
|
|
- default:
|
|
- return -ENODEV;
|
|
- }
|
|
return 0;
|
|
}
|
|
-
|
|
-void sunxi_power_down(void)
|
|
-{
|
|
- switch (pmic) {
|
|
- case GENERIC_H5:
|
|
- /* Turn off as many peripherals and clocks as we can. */
|
|
- sunxi_turn_off_soc(SUNXI_SOC_H5);
|
|
- /* Turn off the pin controller now. */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
|
|
- break;
|
|
- case GENERIC_A64:
|
|
- /* Turn off as many peripherals and clocks as we can. */
|
|
- sunxi_turn_off_soc(SUNXI_SOC_A64);
|
|
- /* Turn off the pin controller now. */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
|
|
- break;
|
|
- case REF_DESIGN_H5:
|
|
- sunxi_turn_off_soc(SUNXI_SOC_H5);
|
|
-
|
|
- /*
|
|
- * Switch PL pins to power off the board:
|
|
- * - PL5 (VCC_IO) -> high
|
|
- * - PL8 (PWR-STB = CPU power supply) -> low
|
|
- * - PL9 (PWR-DRAM) ->low
|
|
- * - PL10 (power LED) -> low
|
|
- * Note: Clearing PL8 will reset the board, so keep it up.
|
|
- */
|
|
- sunxi_set_gpio_out('L', 5, 1);
|
|
- sunxi_set_gpio_out('L', 9, 0);
|
|
- sunxi_set_gpio_out('L', 10, 0);
|
|
-
|
|
- /* Turn off pin controller now. */
|
|
- mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
|
|
-
|
|
- break;
|
|
- case AXP803_RSB:
|
|
- /* (Re-)init RSB in case the rich OS has disabled it. */
|
|
- sunxi_init_platform_r_twi(SUNXI_SOC_A64, true);
|
|
- rsb_init();
|
|
- axp_power_off();
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-
|
|
-}
|
|
diff --git a/plat/allwinner/sun50i_h6/include/core_off_arisc.h b/plat/allwinner/sun50i_h6/include/core_off_arisc.h
|
|
deleted file mode 100644
|
|
index 63a5d8d96..000000000
|
|
--- a/plat/allwinner/sun50i_h6/include/core_off_arisc.h
|
|
+++ /dev/null
|
|
@@ -1,39 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-static uint32_t arisc_core_off[] = {
|
|
- 0x18600000, /* l.movhi r3, <corenr> */
|
|
- 0x18000000, /* l.movhi r0, 0x0 */
|
|
- 0x19a00901, /* l.movhi r13, 0x901 */
|
|
- 0x84ad0080, /* l.lwz r5, 0x80(r13) */
|
|
- 0xe0a51803, /* l.and r5, r5, r3 */
|
|
- 0xe4050000, /* l.sfeq r5, r0 */
|
|
- 0x13fffffd, /* l.bf -12 */
|
|
- 0xb8c30050, /* l.srli r6, r3, 16 */
|
|
-
|
|
- 0xbc060001, /* l.sfeqi r6, 1 */
|
|
- 0x10000005, /* l.bf +20 */
|
|
- 0x19a00700, /* l.movhi r13, 0x700 */
|
|
- 0x84ad0444, /* l.lwz r5, 0x0444(r13) */
|
|
- 0xe0a53004, /* l.or r5, r5, r6 */
|
|
- 0xd40d2c44, /* l.sw 0x0444(r13), r5 */
|
|
-
|
|
- 0x84ad0440, /* l.lwz r5, 0x0440(r13) */
|
|
- 0xacc6ffff, /* l.xori r6, r6, -1 */
|
|
- 0xe0a53003, /* l.and r5, r5, r6 */
|
|
- 0xd40d2c40, /* l.sw 0x0440(r13), r5 */
|
|
-
|
|
- 0xe0c3000f, /* l.ff1 r6, r3 */
|
|
- 0x9cc6ffef, /* l.addi r6, r6, -17 */
|
|
- 0xb8c60002, /* l.slli r6, r6, 2 */
|
|
- 0xe0c66800, /* l.add r6, r6, r13 */
|
|
- 0xa8a000ff, /* l.ori r5, r0, 0xff */
|
|
- 0xd4062c50, /* l.sw 0x0450(r6), r5 */
|
|
-
|
|
- 0xd40d0400, /* l.sw 0x0400(r13), r0 */
|
|
- 0x03ffffff, /* l.j -1 */
|
|
- 0x15000000, /* l.nop */
|
|
-};
|
|
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
|
|
index 443015bac..f1ab84fc4 100644
|
|
--- a/plat/allwinner/sun50i_h6/sunxi_power.c
|
|
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
|
|
@@ -6,14 +6,10 @@
|
|
*/
|
|
|
|
#include <errno.h>
|
|
-#include <string.h>
|
|
|
|
-#include <arch_helpers.h>
|
|
#include <common/debug.h>
|
|
#include <drivers/allwinner/axp.h>
|
|
-#include <drivers/delay_timer.h>
|
|
#include <drivers/mentor/mi2cv.h>
|
|
-#include <lib/mmio.h>
|
|
|
|
#include <sunxi_def.h>
|
|
#include <sunxi_mmap.h>
|
|
@@ -21,11 +17,6 @@
|
|
|
|
#define AXP805_ADDR 0x36
|
|
|
|
-static enum pmic_type {
|
|
- UNKNOWN,
|
|
- AXP805,
|
|
-} pmic;
|
|
-
|
|
int axp_read(uint8_t reg)
|
|
{
|
|
uint8_t val;
|
|
@@ -86,23 +77,7 @@ int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- pmic = AXP805;
|
|
axp_setup_regulators(fdt);
|
|
|
|
return 0;
|
|
}
|
|
-
|
|
-void sunxi_power_down(void)
|
|
-{
|
|
- switch (pmic) {
|
|
- case AXP805:
|
|
- /* Re-initialise after rich OS might have used it. */
|
|
- sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
|
|
- /* initialise mi2cv driver */
|
|
- i2c_init((void *)SUNXI_R_I2C_BASE);
|
|
- axp_power_off();
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-}
|
|
--
|
|
2.28.0
|
|
|