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