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