plat_psci_common.c 4.6 KB

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