e5df015b06fd85b92951db4babd499c7b921a5fa
[project/bcm63xx/atf.git] / lib / extensions / spe / spe.c
1 /*
2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <pubsub.h>
10 #include <spe.h>
11 #include <stdbool.h>
12
13 static inline void psb_csync(void)
14 {
15 /*
16 * The assembler does not yet understand the psb csync mnemonic
17 * so use the equivalent hint instruction.
18 */
19 __asm__ volatile("hint #17");
20 }
21
22 bool spe_supported(void)
23 {
24 uint64_t features;
25
26 features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
27 return (features & ID_AA64DFR0_PMS_MASK) == 1U;
28 }
29
30 void spe_enable(bool el2_unused)
31 {
32 uint64_t v;
33
34 if (!spe_supported())
35 return;
36
37 if (el2_unused) {
38 /*
39 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
40 * profiling controls to EL2.
41 *
42 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
43 * state. Accesses to profiling buffer controls at
44 * Non-secure EL1 are not trapped to EL2.
45 */
46 v = read_mdcr_el2();
47 v &= ~MDCR_EL2_TPMS;
48 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
49 write_mdcr_el2(v);
50 }
51
52 /*
53 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
54 * and disabled in secure state. Accesses to SPE registers at
55 * S-EL1 generate trap exceptions to EL3.
56 */
57 v = read_mdcr_el3();
58 v |= MDCR_NSPB(MDCR_NSPB_EL1);
59 write_mdcr_el3(v);
60 }
61
62 void spe_disable(void)
63 {
64 uint64_t v;
65
66 if (!spe_supported())
67 return;
68
69 /* Drain buffered data */
70 psb_csync();
71 dsbnsh();
72
73 /* Disable profiling buffer */
74 v = read_pmblimitr_el1();
75 v &= ~(1ULL << 0);
76 write_pmblimitr_el1(v);
77 isb();
78 }
79
80 static void *spe_drain_buffers_hook(const void *arg)
81 {
82 if (!spe_supported())
83 return (void *)-1;
84
85 /* Drain buffered data */
86 psb_csync();
87 dsbnsh();
88
89 return (void *)0;
90 }
91
92 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);