xref: /rk3399_ARM-atf/lib/extensions/spe/spe.c (revision 2ff8fbf3b0d1403afab9b5316fd7ea40859c889c)
1281a08ccSDimitris Papastamos /*
2*2ff8fbf3SDimitris Papastamos  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3281a08ccSDimitris Papastamos  *
4281a08ccSDimitris Papastamos  * SPDX-License-Identifier: BSD-3-Clause
5281a08ccSDimitris Papastamos  */
6281a08ccSDimitris Papastamos 
7281a08ccSDimitris Papastamos #include <arch.h>
8281a08ccSDimitris Papastamos #include <arch_helpers.h>
9281a08ccSDimitris Papastamos #include <pubsub.h>
10281a08ccSDimitris Papastamos 
11281a08ccSDimitris Papastamos /*
12281a08ccSDimitris Papastamos  * The assembler does not yet understand the psb csync mnemonic
13281a08ccSDimitris Papastamos  * so use the equivalent hint instruction.
14281a08ccSDimitris Papastamos  */
15281a08ccSDimitris Papastamos #define psb_csync()	asm volatile("hint #17")
16281a08ccSDimitris Papastamos 
17*2ff8fbf3SDimitris Papastamos int spe_supported(void)
18281a08ccSDimitris Papastamos {
19281a08ccSDimitris Papastamos 	uint64_t features;
20281a08ccSDimitris Papastamos 
21281a08ccSDimitris Papastamos 	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
22*2ff8fbf3SDimitris Papastamos 	return (features & ID_AA64DFR0_PMS_MASK) == 1;
23*2ff8fbf3SDimitris Papastamos }
24*2ff8fbf3SDimitris Papastamos 
25*2ff8fbf3SDimitris Papastamos void spe_enable(int el2_unused)
26*2ff8fbf3SDimitris Papastamos {
27281a08ccSDimitris Papastamos 	uint64_t v;
28281a08ccSDimitris Papastamos 
29*2ff8fbf3SDimitris Papastamos 	if (!spe_supported())
30*2ff8fbf3SDimitris Papastamos 		return;
31*2ff8fbf3SDimitris Papastamos 
32281a08ccSDimitris Papastamos 	if (el2_unused) {
33281a08ccSDimitris Papastamos 		/*
34281a08ccSDimitris Papastamos 		 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
35281a08ccSDimitris Papastamos 		 * profiling controls to EL2.
36281a08ccSDimitris Papastamos 		 *
37281a08ccSDimitris Papastamos 		 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
38281a08ccSDimitris Papastamos 		 * state. Accesses to profiling buffer controls at
39281a08ccSDimitris Papastamos 		 * Non-secure EL1 are not trapped to EL2.
40281a08ccSDimitris Papastamos 		 */
41281a08ccSDimitris Papastamos 		v = read_mdcr_el2();
42281a08ccSDimitris Papastamos 		v &= ~MDCR_EL2_TPMS;
43281a08ccSDimitris Papastamos 		v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
44281a08ccSDimitris Papastamos 		write_mdcr_el2(v);
45281a08ccSDimitris Papastamos 	}
46281a08ccSDimitris Papastamos 
47281a08ccSDimitris Papastamos 	/*
48281a08ccSDimitris Papastamos 	 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
49281a08ccSDimitris Papastamos 	 * and disabled in secure state. Accesses to SPE registers at
50281a08ccSDimitris Papastamos 	 * S-EL1 generate trap exceptions to EL3.
51281a08ccSDimitris Papastamos 	 */
52281a08ccSDimitris Papastamos 	v = read_mdcr_el3();
53281a08ccSDimitris Papastamos 	v |= MDCR_NSPB(MDCR_NSPB_EL1);
54281a08ccSDimitris Papastamos 	write_mdcr_el3(v);
55281a08ccSDimitris Papastamos }
56281a08ccSDimitris Papastamos 
57281a08ccSDimitris Papastamos void spe_disable(void)
58281a08ccSDimitris Papastamos {
59281a08ccSDimitris Papastamos 	uint64_t v;
60281a08ccSDimitris Papastamos 
61*2ff8fbf3SDimitris Papastamos 	if (!spe_supported())
62*2ff8fbf3SDimitris Papastamos 		return;
63*2ff8fbf3SDimitris Papastamos 
64281a08ccSDimitris Papastamos 	/* Drain buffered data */
65281a08ccSDimitris Papastamos 	psb_csync();
66281a08ccSDimitris Papastamos 	dsbnsh();
67281a08ccSDimitris Papastamos 
68281a08ccSDimitris Papastamos 	/* Disable profiling buffer */
69281a08ccSDimitris Papastamos 	v = read_pmblimitr_el1();
70281a08ccSDimitris Papastamos 	v &= ~(1ULL << 0);
71281a08ccSDimitris Papastamos 	write_pmblimitr_el1(v);
72281a08ccSDimitris Papastamos 	isb();
73281a08ccSDimitris Papastamos }
74281a08ccSDimitris Papastamos 
75281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg)
76281a08ccSDimitris Papastamos {
77*2ff8fbf3SDimitris Papastamos 	if (!spe_supported())
78*2ff8fbf3SDimitris Papastamos 		return (void *)-1;
79281a08ccSDimitris Papastamos 
80281a08ccSDimitris Papastamos 	/* Drain buffered data */
81281a08ccSDimitris Papastamos 	psb_csync();
82281a08ccSDimitris Papastamos 	dsbnsh();
83281a08ccSDimitris Papastamos 	return 0;
84281a08ccSDimitris Papastamos }
85281a08ccSDimitris Papastamos 
86281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
87