blob: a272aaf7ae7cd9083cf392b9ebde7914077f822d [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <amu.h>
8#include <arch.h>
9#include <arch_helpers.h>
10#include <assert.h>
11#include <debug.h>
12#include <irq.h>
13#include <plat_topology.h>
14#include <platform.h>
15#include <power_management.h>
16#include <tftf_lib.h>
17#include <timer.h>
18
19#define SUSPEND_TIME_1_SEC 1000
20
21static volatile int wakeup_irq_received[PLATFORM_CORE_COUNT];
22
23/* Dummy timer handler that sets a flag to check it has been called. */
24static int suspend_wakeup_handler(void *data)
25{
26 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
27 unsigned int core_pos = platform_get_core_pos(core_mpid);
28
29 assert(wakeup_irq_received[core_pos] == 0);
30
31 wakeup_irq_received[core_pos] = 1;
32
33 return 0;
34}
35
36/*
37 * Helper function to suspend a CPU to power level 0 and wake it up with
38 * a timer.
39 */
40static test_result_t suspend_and_resume_this_cpu(void)
41{
42 uint32_t stateid;
43 int psci_ret;
44 test_result_t result = TEST_RESULT_SUCCESS;
45
46 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
47 unsigned int core_pos = platform_get_core_pos(core_mpid);
48
49 /* Prepare wakeup timer. IRQs need to be enabled. */
50 wakeup_irq_received[core_pos] = 0;
51
52 tftf_timer_register_handler(suspend_wakeup_handler);
53
54 /* Program timer to fire interrupt after timer expires */
55 tftf_program_timer(SUSPEND_TIME_1_SEC);
56
57 /*
58 * Suspend the calling CPU to power level 0 and power
59 * state.
60 */
61 psci_ret = tftf_psci_make_composite_state_id(PSTATE_AFF_LVL_0,
62 PSTATE_TYPE_POWERDOWN,
63 &stateid);
64 if (psci_ret != PSCI_E_SUCCESS) {
65 mp_printf("Failed to make composite state ID @ CPU %d. rc = %x\n",
66 core_pos, psci_ret);
67 result = TEST_RESULT_FAIL;
68 } else {
69 unsigned int power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
70 PSTATE_TYPE_POWERDOWN, stateid);
71 psci_ret = tftf_cpu_suspend(power_state);
72
73 if (!wakeup_irq_received[core_pos]) {
74 mp_printf("Didn't receive wakeup IRQ in CPU %d.\n",
75 core_pos);
76 result = TEST_RESULT_FAIL;
77 }
78
79 if (psci_ret != PSCI_E_SUCCESS) {
80 mp_printf("Failed to suspend from CPU %d. ret: %x\n",
81 core_pos, psci_ret);
82 result = TEST_RESULT_FAIL;
83 }
84 }
85
86 /* Wake up. Remove timer after waking up.*/
87 tftf_cancel_timer();
88 tftf_timer_unregister_handler();
89
90 return result;
91}
92
93/*
94 * Check that group0/group1 counters are non-zero. As EL3
95 * has enabled the counters before the first entry to NS world,
96 * the counters should have increased by the time we reach this
97 * test case.
98 */
99test_result_t test_amu_nonzero_ctr(void)
100{
101 int i;
102
103 if (!amu_supported())
104 return TEST_RESULT_SKIPPED;
105
106 /* If counters are not enabled, then skip the test */
John Tsichritzis68759a82019-05-12 15:10:27 +0100107 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200108 return TEST_RESULT_SKIPPED;
109
110 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
111 uint64_t v;
112
113 v = amu_group0_cnt_read(i);
114 if (v == 0) {
115 tftf_testcase_printf("Group0 counter cannot be 0\n");
116 return TEST_RESULT_FAIL;
117 }
118 }
119
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200120 return TEST_RESULT_SUCCESS;
121}
122
123/*
124 * Check that the counters are non-decreasing during
125 * a suspend/resume cycle.
126 */
127test_result_t test_amu_suspend_resume(void)
128{
129 uint64_t group0_ctrs[AMU_GROUP0_MAX_NR_COUNTERS];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200130 int i;
131
132 if (!amu_supported())
133 return TEST_RESULT_SKIPPED;
134
135 /* If counters are not enabled, then skip the test */
John Tsichritzis68759a82019-05-12 15:10:27 +0100136 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200137 return TEST_RESULT_SKIPPED;
138
139 /* Save counters values before suspend */
140 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
141 group0_ctrs[i] = amu_group0_cnt_read(i);
142
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200143 /* Suspend/resume current core */
144 suspend_and_resume_this_cpu();
145
146 /*
147 * Check if counter values are >= than the stored values.
148 * If they are not, the AMU context save/restore in EL3 is buggy.
149 */
150 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
151 uint64_t v;
152
153 v = amu_group0_cnt_read(i);
154 if (v < group0_ctrs[i]) {
155 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
156 (unsigned long long)group0_ctrs[i],
157 (unsigned long long)v);
158 return TEST_RESULT_FAIL;
159 }
160 }
161
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200162 return TEST_RESULT_SUCCESS;
163}