xref: /rk3399_ARM-atf/lib/extensions/spe/spe.c (revision 1af540ef2a09797c3a22c40c340facd4b2f47c2f)
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 
12 /*
13  * The assembler does not yet understand the psb csync mnemonic
14  * so use the equivalent hint instruction.
15  */
16 #define psb_csync()	asm volatile("hint #17")
17 
18 void spe_enable(int el2_unused)
19 {
20 	uint64_t features;
21 
22 	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
23 	if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
24 		uint64_t v;
25 
26 		if (el2_unused) {
27 			/*
28 			 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
29 			 * profiling controls to EL2.
30 			 *
31 			 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
32 			 * state. Accesses to profiling buffer controls at
33 			 * Non-secure EL1 are not trapped to EL2.
34 			 */
35 			v = read_mdcr_el2();
36 			v &= ~MDCR_EL2_TPMS;
37 			v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
38 			write_mdcr_el2(v);
39 		}
40 
41 		/*
42 		 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
43 		 * and disabled in secure state. Accesses to SPE registers at
44 		 * S-EL1 generate trap exceptions to EL3.
45 		 */
46 		v = read_mdcr_el3();
47 		v |= MDCR_NSPB(MDCR_NSPB_EL1);
48 		write_mdcr_el3(v);
49 	}
50 }
51 
52 void spe_disable(void)
53 {
54 	uint64_t features;
55 
56 	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
57 	if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
58 		uint64_t v;
59 
60 		/* Drain buffered data */
61 		psb_csync();
62 		dsbnsh();
63 
64 		/* Disable profiling buffer */
65 		v = read_pmblimitr_el1();
66 		v &= ~(1ULL << 0);
67 		write_pmblimitr_el1(v);
68 		isb();
69 	}
70 }
71 
72 static void *spe_drain_buffers_hook(const void *arg)
73 {
74 	uint64_t features;
75 
76 	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
77 	if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
78 		/* Drain buffered data */
79 		psb_csync();
80 		dsbnsh();
81 	}
82 
83 	return 0;
84 }
85 
86 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
87