1e2469d82SVarun Wadekar /*
2e2469d82SVarun Wadekar * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3e2469d82SVarun Wadekar *
4e2469d82SVarun Wadekar * SPDX-License-Identifier: BSD-3-Clause
5e2469d82SVarun Wadekar */
6e2469d82SVarun Wadekar
7e2469d82SVarun Wadekar #include <assert.h>
8e2469d82SVarun Wadekar
9e2469d82SVarun Wadekar #include <arch_helpers.h>
10e2469d82SVarun Wadekar #include <common/debug.h>
11e2469d82SVarun Wadekar #include <lib/mmio.h>
12e2469d82SVarun Wadekar
13e2469d82SVarun Wadekar #include <pmc.h>
14e2469d82SVarun Wadekar #include <tegra_def.h>
15e2469d82SVarun Wadekar
16e2469d82SVarun Wadekar #define RESET_ENABLE 0x10U
17e2469d82SVarun Wadekar
18e2469d82SVarun Wadekar /* Module IDs used during power ungate procedure */
19e2469d82SVarun Wadekar static const uint32_t pmc_cpu_powergate_id[4] = {
20e2469d82SVarun Wadekar 14, /* CPU 0 */
21e2469d82SVarun Wadekar 9, /* CPU 1 */
22e2469d82SVarun Wadekar 10, /* CPU 2 */
23e2469d82SVarun Wadekar 11 /* CPU 3 */
24e2469d82SVarun Wadekar };
25e2469d82SVarun Wadekar
26e2469d82SVarun Wadekar /*******************************************************************************
27e2469d82SVarun Wadekar * Power ungate CPU to start the boot process. CPU reset vectors must be
28e2469d82SVarun Wadekar * populated before calling this function.
29e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_cpu_on(int32_t cpu)30e2469d82SVarun Wadekar void tegra_pmc_cpu_on(int32_t cpu)
31e2469d82SVarun Wadekar {
32e2469d82SVarun Wadekar uint32_t val;
33e2469d82SVarun Wadekar
34e2469d82SVarun Wadekar /*
35e2469d82SVarun Wadekar * Check if CPU is already power ungated
36e2469d82SVarun Wadekar */
37e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
38e2469d82SVarun Wadekar if ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U) {
39e2469d82SVarun Wadekar /*
40e2469d82SVarun Wadekar * The PMC deasserts the START bit when it starts the power
41e2469d82SVarun Wadekar * ungate process. Loop till no power toggle is in progress.
42e2469d82SVarun Wadekar */
43e2469d82SVarun Wadekar do {
44e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
45e2469d82SVarun Wadekar } while ((val & PMC_TOGGLE_START) != 0U);
46e2469d82SVarun Wadekar
47e2469d82SVarun Wadekar /*
48e2469d82SVarun Wadekar * Start the power ungate procedure
49e2469d82SVarun Wadekar */
50e2469d82SVarun Wadekar val = pmc_cpu_powergate_id[cpu] | PMC_TOGGLE_START;
51e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_PWRGATE_TOGGLE, val);
52e2469d82SVarun Wadekar
53e2469d82SVarun Wadekar /*
54e2469d82SVarun Wadekar * The PMC deasserts the START bit when it starts the power
55e2469d82SVarun Wadekar * ungate process. Loop till powergate START bit is asserted.
56e2469d82SVarun Wadekar */
57e2469d82SVarun Wadekar do {
58e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
59e2469d82SVarun Wadekar } while ((val & (1U << 8)) != 0U);
60e2469d82SVarun Wadekar
61e2469d82SVarun Wadekar /* loop till the CPU is power ungated */
62e2469d82SVarun Wadekar do {
63e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
64e2469d82SVarun Wadekar } while ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U);
65e2469d82SVarun Wadekar }
66e2469d82SVarun Wadekar }
67e2469d82SVarun Wadekar
68e2469d82SVarun Wadekar /*******************************************************************************
69e2469d82SVarun Wadekar * Setup CPU vectors for resume from deep sleep
70e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_cpu_setup(uint64_t reset_addr)71e2469d82SVarun Wadekar void tegra_pmc_cpu_setup(uint64_t reset_addr)
72e2469d82SVarun Wadekar {
73e2469d82SVarun Wadekar uint32_t val;
74e2469d82SVarun Wadekar
75e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_SECURE_SCRATCH34,
76e2469d82SVarun Wadekar ((uint32_t)reset_addr & 0xFFFFFFFFU) | 1U);
77e2469d82SVarun Wadekar val = (uint32_t)(reset_addr >> 32U);
78e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_SECURE_SCRATCH35, val & 0x7FFU);
79e2469d82SVarun Wadekar }
80e2469d82SVarun Wadekar
81e2469d82SVarun Wadekar /*******************************************************************************
82e2469d82SVarun Wadekar * Lock CPU vectors to restrict further writes
83e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_lock_cpu_vectors(void)84e2469d82SVarun Wadekar void tegra_pmc_lock_cpu_vectors(void)
85e2469d82SVarun Wadekar {
86e2469d82SVarun Wadekar uint32_t val;
87e2469d82SVarun Wadekar
88e2469d82SVarun Wadekar /* lock PMC_SECURE_SCRATCH22 */
89e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_SECURE_DISABLE2);
90e2469d82SVarun Wadekar val |= PMC_SECURE_DISABLE2_WRITE22_ON;
91e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_SECURE_DISABLE2, val);
92e2469d82SVarun Wadekar
93e2469d82SVarun Wadekar /* lock PMC_SECURE_SCRATCH34/35 */
94e2469d82SVarun Wadekar val = tegra_pmc_read_32(PMC_SECURE_DISABLE3);
95e2469d82SVarun Wadekar val |= (PMC_SECURE_DISABLE3_WRITE34_ON |
96e2469d82SVarun Wadekar PMC_SECURE_DISABLE3_WRITE35_ON);
97e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_SECURE_DISABLE3, val);
98e2469d82SVarun Wadekar }
99e2469d82SVarun Wadekar
100e2469d82SVarun Wadekar /*******************************************************************************
101e2469d82SVarun Wadekar * Find out if this is the last standing CPU
102e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_is_last_on_cpu(void)103e2469d82SVarun Wadekar bool tegra_pmc_is_last_on_cpu(void)
104e2469d82SVarun Wadekar {
105e2469d82SVarun Wadekar int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
106*9a90d720SElyes Haouas uint32_t val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
107e2469d82SVarun Wadekar bool status = true;
108e2469d82SVarun Wadekar
109e2469d82SVarun Wadekar /* check if this is the last standing CPU */
110e2469d82SVarun Wadekar for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) {
111e2469d82SVarun Wadekar
112e2469d82SVarun Wadekar /* skip the current CPU */
113e2469d82SVarun Wadekar if (i == cpu)
114e2469d82SVarun Wadekar continue;
115e2469d82SVarun Wadekar
116e2469d82SVarun Wadekar /* are other CPUs already power gated? */
117e2469d82SVarun Wadekar if ((val & ((uint32_t)1 << pmc_cpu_powergate_id[i])) != 0U) {
118e2469d82SVarun Wadekar status = false;
119e2469d82SVarun Wadekar }
120e2469d82SVarun Wadekar }
121e2469d82SVarun Wadekar
122e2469d82SVarun Wadekar return status;
123e2469d82SVarun Wadekar }
124e2469d82SVarun Wadekar
125e2469d82SVarun Wadekar /*******************************************************************************
126e2469d82SVarun Wadekar * Handler to be called on exiting System suspend. Right now only DPD registers
127e2469d82SVarun Wadekar * are cleared.
128e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_resume(void)129e2469d82SVarun Wadekar void tegra_pmc_resume(void)
130e2469d82SVarun Wadekar {
131e2469d82SVarun Wadekar
132e2469d82SVarun Wadekar /* Clear DPD sample */
133e2469d82SVarun Wadekar mmio_write_32((TEGRA_PMC_BASE + PMC_IO_DPD_SAMPLE), 0x0);
134e2469d82SVarun Wadekar
135e2469d82SVarun Wadekar /* Clear DPD Enable */
136e2469d82SVarun Wadekar mmio_write_32((TEGRA_PMC_BASE + PMC_DPD_ENABLE_0), 0x0);
137e2469d82SVarun Wadekar }
138e2469d82SVarun Wadekar
139e2469d82SVarun Wadekar /*******************************************************************************
140e2469d82SVarun Wadekar * Restart the system
141e2469d82SVarun Wadekar ******************************************************************************/
tegra_pmc_system_reset(void)142e2469d82SVarun Wadekar __dead2 void tegra_pmc_system_reset(void)
143e2469d82SVarun Wadekar {
144e2469d82SVarun Wadekar uint32_t reg;
145e2469d82SVarun Wadekar
146e2469d82SVarun Wadekar reg = tegra_pmc_read_32(PMC_CONFIG);
147e2469d82SVarun Wadekar reg |= RESET_ENABLE; /* restart */
148e2469d82SVarun Wadekar tegra_pmc_write_32(PMC_CONFIG, reg);
149e2469d82SVarun Wadekar wfi();
150e2469d82SVarun Wadekar
151e2469d82SVarun Wadekar ERROR("Tegra System Reset: operation not handled.\n");
152e2469d82SVarun Wadekar panic();
153e2469d82SVarun Wadekar }
154