mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 12:33:41 +00:00
ffdf9f9ae0
This is based on Thierry Reding's work and uses Ian Campell's preparatory patches. It comes with full support for CPU_ON/OFF PSCI services. The algorithm used in this version for turning CPUs on and off was proposed by Peter De Schrijver and Thierry Reding in http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/210881. It consists of first enabling CPU1..3 via the PMC, just to powergate them again with the help of the Flow Controller. Once the Flow Controller is in place, we can leave the PMC alone while processing CPU_ON and CPU_OFF PSCI requests. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Tom Warren <twarren@nvidia.com>
59 lines
1.7 KiB
C
59 lines
1.7 KiB
C
/*
|
|
* (C) Copyright 2015, Siemens AG
|
|
* Author: Jan Kiszka <jan.kiszka@siemens.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <asm/psci.h>
|
|
#include <asm/arch/flow.h>
|
|
#include <asm/arch/powergate.h>
|
|
#include <asm/arch-tegra/ap.h>
|
|
#include <asm/arch-tegra/pmc.h>
|
|
|
|
static void park_cpu(void)
|
|
{
|
|
while (1)
|
|
asm volatile("wfi");
|
|
}
|
|
|
|
/**
|
|
* Initialize power management for application processors
|
|
*/
|
|
void psci_board_init(void)
|
|
{
|
|
struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
|
|
|
|
writel((u32)park_cpu, EXCEP_VECTOR_CPU_RESET_VECTOR);
|
|
|
|
/*
|
|
* The naturally expected order of putting these CPUs under Flow
|
|
* Controller regime would be
|
|
* - configure the Flow Controller
|
|
* - power up the CPUs
|
|
* - wait for the CPUs to hit wfi and be powered down again
|
|
*
|
|
* However, this doesn't work in practice. We rather need to power them
|
|
* up first and park them in wfi. While they are waiting there, we can
|
|
* indeed program the Flow Controller to powergate them on wfi, which
|
|
* will then happen immediately as they are already in that state.
|
|
*/
|
|
tegra_powergate_power_on(TEGRA_POWERGATE_CPU1);
|
|
tegra_powergate_power_on(TEGRA_POWERGATE_CPU2);
|
|
tegra_powergate_power_on(TEGRA_POWERGATE_CPU3);
|
|
|
|
writel((2 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu1_csr);
|
|
writel((4 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu2_csr);
|
|
writel((8 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu3_csr);
|
|
|
|
writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
|
|
writel(EVENT_MODE_STOP, &flow->halt_cpu2_events);
|
|
writel(EVENT_MODE_STOP, &flow->halt_cpu3_events);
|
|
|
|
while (!(readl(&flow->cpu1_csr) & CSR_PWR_OFF_STS) ||
|
|
!(readl(&flow->cpu2_csr) & CSR_PWR_OFF_STS) ||
|
|
!(readl(&flow->cpu3_csr) & CSR_PWR_OFF_STS))
|
|
/* wait */;
|
|
}
|