1 /* 2 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <assert.h> 9 #include <platform.h> 10 #include <pmf.h> 11 #include <psci.h> 12 13 #if ENABLE_PSCI_STAT && ENABLE_PMF 14 #pragma weak plat_psci_stat_accounting_start 15 #pragma weak plat_psci_stat_accounting_stop 16 #pragma weak plat_psci_stat_get_residency 17 18 /* Ticks elapsed in one second by a signal of 1 MHz */ 19 #define MHZ_TICKS_PER_SEC 1000000 20 21 /* Following are used as ID's to capture time-stamp */ 22 #define PSCI_STAT_ID_ENTER_LOW_PWR 0 23 #define PSCI_STAT_ID_EXIT_LOW_PWR 1 24 #define PSCI_STAT_TOTAL_IDS 2 25 26 PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS, 27 PMF_STORE_ENABLE) 28 29 /* 30 * This function calculates the stats residency in microseconds, 31 * taking in account the wrap around condition. 32 */ 33 static u_register_t calc_stat_residency(unsigned long long pwrupts, 34 unsigned long long pwrdnts) 35 { 36 /* The divisor to use to convert raw timestamp into microseconds. */ 37 u_register_t residency_div; 38 u_register_t res; 39 40 /* 41 * Calculate divisor so that it can be directly used to 42 * convert time-stamp into microseconds. 43 */ 44 residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC; 45 assert(residency_div); 46 47 if (pwrupts < pwrdnts) 48 res = UINT64_MAX - pwrdnts + pwrupts; 49 else 50 res = pwrupts - pwrdnts; 51 52 return res / residency_div; 53 } 54 55 /* 56 * Capture timestamp before entering a low power state. 57 * No cache maintenance is required when capturing the timestamp. 58 * Cache maintenance may be needed when reading these timestamps. 59 */ 60 void plat_psci_stat_accounting_start( 61 __unused const psci_power_state_t *state_info) 62 { 63 assert(state_info); 64 PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR, 65 PMF_NO_CACHE_MAINT); 66 } 67 68 /* 69 * Capture timestamp after exiting a low power state. 70 * No cache maintenance is required when capturing the timestamp. 71 * Cache maintenance may be needed when reading these timestamps. 72 */ 73 void plat_psci_stat_accounting_stop( 74 __unused const psci_power_state_t *state_info) 75 { 76 assert(state_info); 77 PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR, 78 PMF_NO_CACHE_MAINT); 79 } 80 81 /* 82 * Calculate the residency for the given level and power state 83 * information. 84 */ 85 u_register_t plat_psci_stat_get_residency(unsigned int lvl, 86 const psci_power_state_t *state_info, 87 int last_cpu_idx) 88 { 89 plat_local_state_t state; 90 unsigned long long pwrup_ts = 0, pwrdn_ts = 0; 91 unsigned int pmf_flags; 92 93 assert(lvl >= PSCI_CPU_PWR_LVL && lvl <= PLAT_MAX_PWR_LVL); 94 assert(state_info); 95 assert(last_cpu_idx >= 0 && last_cpu_idx <= PLATFORM_CORE_COUNT); 96 97 if (lvl == PSCI_CPU_PWR_LVL) 98 assert(last_cpu_idx == plat_my_core_pos()); 99 100 /* 101 * If power down is requested, then timestamp capture will 102 * be with caches OFF. Hence we have to do cache maintenance 103 * when reading the timestamp. 104 */ 105 state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]; 106 if (is_local_state_off(state)) { 107 pmf_flags = PMF_CACHE_MAINT; 108 } else { 109 assert(is_local_state_retn(state)); 110 pmf_flags = PMF_NO_CACHE_MAINT; 111 } 112 113 PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, 114 PSCI_STAT_ID_ENTER_LOW_PWR, 115 last_cpu_idx, 116 pmf_flags, 117 pwrdn_ts); 118 119 PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, 120 PSCI_STAT_ID_EXIT_LOW_PWR, 121 plat_my_core_pos(), 122 pmf_flags, 123 pwrup_ts); 124 125 return calc_stat_residency(pwrup_ts, pwrdn_ts); 126 } 127 #endif /* ENABLE_PSCI_STAT && ENABLE_PMF */ 128 129 /* 130 * The PSCI generic code uses this API to let the platform participate in state 131 * coordination during a power management operation. It compares the platform 132 * specific local power states requested by each cpu for a given power domain 133 * and returns the coordinated target power state that the domain should 134 * enter. A platform assigns a number to a local power state. This default 135 * implementation assumes that the platform assigns these numbers in order of 136 * increasing depth of the power state i.e. for two power states X & Y, if X < Y 137 * then X represents a shallower power state than Y. As a result, the 138 * coordinated target local power state for a power domain will be the minimum 139 * of the requested local power states. 140 */ 141 plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, 142 const plat_local_state_t *states, 143 unsigned int ncpu) 144 { 145 plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; 146 147 assert(ncpu); 148 149 do { 150 temp = *states++; 151 if (temp < target) 152 target = temp; 153 } while (--ncpu); 154 155 return target; 156 } 157