1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2015, Siemens AG
3*4882a593Smuzhiyun * Author: Jan Kiszka <jan.kiszka@siemens.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <asm/io.h>
10*4882a593Smuzhiyun #include <asm/psci.h>
11*4882a593Smuzhiyun #include <asm/arch/flow.h>
12*4882a593Smuzhiyun #include <asm/arch/powergate.h>
13*4882a593Smuzhiyun #include <asm/arch-tegra/ap.h>
14*4882a593Smuzhiyun #include <asm/arch-tegra/pmc.h>
15*4882a593Smuzhiyun
park_cpu(void)16*4882a593Smuzhiyun static void park_cpu(void)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun while (1)
19*4882a593Smuzhiyun asm volatile("wfi");
20*4882a593Smuzhiyun }
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /**
23*4882a593Smuzhiyun * Initialize power management for application processors
24*4882a593Smuzhiyun */
psci_board_init(void)25*4882a593Smuzhiyun void psci_board_init(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun writel((u32)park_cpu, EXCEP_VECTOR_CPU_RESET_VECTOR);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun * The naturally expected order of putting these CPUs under Flow
33*4882a593Smuzhiyun * Controller regime would be
34*4882a593Smuzhiyun * - configure the Flow Controller
35*4882a593Smuzhiyun * - power up the CPUs
36*4882a593Smuzhiyun * - wait for the CPUs to hit wfi and be powered down again
37*4882a593Smuzhiyun *
38*4882a593Smuzhiyun * However, this doesn't work in practice. We rather need to power them
39*4882a593Smuzhiyun * up first and park them in wfi. While they are waiting there, we can
40*4882a593Smuzhiyun * indeed program the Flow Controller to powergate them on wfi, which
41*4882a593Smuzhiyun * will then happen immediately as they are already in that state.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun tegra_powergate_power_on(TEGRA_POWERGATE_CPU1);
44*4882a593Smuzhiyun tegra_powergate_power_on(TEGRA_POWERGATE_CPU2);
45*4882a593Smuzhiyun tegra_powergate_power_on(TEGRA_POWERGATE_CPU3);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun writel((2 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu1_csr);
48*4882a593Smuzhiyun writel((4 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu2_csr);
49*4882a593Smuzhiyun writel((8 << CSR_WAIT_WFI_SHIFT) | CSR_ENABLE, &flow->cpu3_csr);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
52*4882a593Smuzhiyun writel(EVENT_MODE_STOP, &flow->halt_cpu2_events);
53*4882a593Smuzhiyun writel(EVENT_MODE_STOP, &flow->halt_cpu3_events);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun while (!(readl(&flow->cpu1_csr) & CSR_PWR_OFF_STS) ||
56*4882a593Smuzhiyun !(readl(&flow->cpu2_csr) & CSR_PWR_OFF_STS) ||
57*4882a593Smuzhiyun !(readl(&flow->cpu3_csr) & CSR_PWR_OFF_STS))
58*4882a593Smuzhiyun /* wait */;
59*4882a593Smuzhiyun }
60