blob: 0e00faaf5e803f15c5d72a5f1a6f54c96281ce47 [file] [log] [blame]
Soby Mathew0d786072016-03-24 16:56:29 +00001/*
dp-arm66abfbe2017-01-31 13:01:04 +00002 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
Soby Mathew0d786072016-03-24 16:56:29 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch.h>
32#include <assert.h>
33#include <platform.h>
dp-arm66abfbe2017-01-31 13:01:04 +000034#include <pmf.h>
Soby Mathew0d786072016-03-24 16:56:29 +000035#include <psci.h>
36
dp-arm66abfbe2017-01-31 13:01:04 +000037#if ENABLE_PSCI_STAT && ENABLE_PMF
38#pragma weak plat_psci_stat_accounting_start
39#pragma weak plat_psci_stat_accounting_stop
40#pragma weak plat_psci_stat_get_residency
41
42/* Ticks elapsed in one second by a signal of 1 MHz */
43#define MHZ_TICKS_PER_SEC 1000000
44
45/* Following are used as ID's to capture time-stamp */
46#define PSCI_STAT_ID_ENTER_LOW_PWR 0
47#define PSCI_STAT_ID_EXIT_LOW_PWR 1
48#define PSCI_STAT_TOTAL_IDS 2
49
50PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS,
51 PMF_STORE_ENABLE)
52
53/*
54 * This function calculates the stats residency in microseconds,
55 * taking in account the wrap around condition.
56 */
57static u_register_t calc_stat_residency(unsigned long long pwrupts,
58 unsigned long long pwrdnts)
59{
60 /* The divisor to use to convert raw timestamp into microseconds. */
61 u_register_t residency_div;
62 u_register_t res;
63
64 /*
65 * Calculate divisor so that it can be directly used to
66 * convert time-stamp into microseconds.
67 */
68 residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
69 assert(residency_div);
70
71 if (pwrupts < pwrdnts)
72 res = UINT64_MAX - pwrdnts + pwrupts;
73 else
74 res = pwrupts - pwrdnts;
75
76 return res / residency_div;
77}
78
79/*
80 * Capture timestamp before entering a low power state.
81 * No cache maintenance is required when capturing the timestamp.
82 * Cache maintenance may be needed when reading these timestamps.
83 */
84void plat_psci_stat_accounting_start(
85 __unused const psci_power_state_t *state_info)
86{
87 assert(state_info);
88 PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
89 PMF_NO_CACHE_MAINT);
90}
91
92/*
93 * Capture timestamp after exiting a low power state.
94 * No cache maintenance is required when capturing the timestamp.
95 * Cache maintenance may be needed when reading these timestamps.
96 */
97void plat_psci_stat_accounting_stop(
98 __unused const psci_power_state_t *state_info)
99{
100 assert(state_info);
101 PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
102 PMF_NO_CACHE_MAINT);
103}
104
105/*
106 * Calculate the residency for the given level and power state
107 * information.
108 */
109u_register_t plat_psci_stat_get_residency(unsigned int lvl,
110 const psci_power_state_t *state_info,
111 int last_cpu_idx)
112{
113 plat_local_state_t state;
114 unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
115 unsigned int pmf_flags;
116
117 assert(lvl >= PSCI_CPU_PWR_LVL && lvl <= PLAT_MAX_PWR_LVL);
118 assert(state_info);
119 assert(last_cpu_idx >= 0 && last_cpu_idx <= PLATFORM_CORE_COUNT);
120
121 if (lvl == PSCI_CPU_PWR_LVL)
122 assert(last_cpu_idx == plat_my_core_pos());
123
124 /*
125 * If power down is requested, then timestamp capture will
126 * be with caches OFF. Hence we have to do cache maintenance
127 * when reading the timestamp.
128 */
129 state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
130 if (is_local_state_off(state)) {
131 pmf_flags = PMF_CACHE_MAINT;
132 } else {
133 assert(is_local_state_retn(state));
134 pmf_flags = PMF_NO_CACHE_MAINT;
135 }
136
137 PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
138 PSCI_STAT_ID_ENTER_LOW_PWR,
139 last_cpu_idx,
140 pmf_flags,
141 pwrdn_ts);
142
143 PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
144 PSCI_STAT_ID_EXIT_LOW_PWR,
145 plat_my_core_pos(),
146 pmf_flags,
147 pwrup_ts);
148
149 return calc_stat_residency(pwrup_ts, pwrdn_ts);
150}
151#endif /* ENABLE_PSCI_STAT && ENABLE_PMF */
152
Soby Mathew0d786072016-03-24 16:56:29 +0000153/*
154 * The PSCI generic code uses this API to let the platform participate in state
155 * coordination during a power management operation. It compares the platform
156 * specific local power states requested by each cpu for a given power domain
157 * and returns the coordinated target power state that the domain should
158 * enter. A platform assigns a number to a local power state. This default
159 * implementation assumes that the platform assigns these numbers in order of
160 * increasing depth of the power state i.e. for two power states X & Y, if X < Y
161 * then X represents a shallower power state than Y. As a result, the
162 * coordinated target local power state for a power domain will be the minimum
163 * of the requested local power states.
164 */
165plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
166 const plat_local_state_t *states,
167 unsigned int ncpu)
168{
169 plat_local_state_t target = PLAT_MAX_OFF_STATE, temp;
170
171 assert(ncpu);
172
173 do {
174 temp = *states++;
175 if (temp < target)
176 target = temp;
177 } while (--ncpu);
178
179 return target;
180}