xref: /rk3399_ARM-atf/lib/extensions/spe/spe.c (revision 40daecc1be51383c806c0ac953303e47026abcac)
1281a08ccSDimitris Papastamos /*
22ff8fbf3SDimitris 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>
107fabe1a8SRoberto Vargas #include <spe.h>
11*40daecc1SAntonio Nino Diaz #include <stdbool.h>
12281a08ccSDimitris Papastamos 
13*40daecc1SAntonio Nino Diaz static inline void psb_csync(void)
14*40daecc1SAntonio Nino Diaz {
15281a08ccSDimitris Papastamos 	/*
16281a08ccSDimitris Papastamos 	 * The assembler does not yet understand the psb csync mnemonic
17281a08ccSDimitris Papastamos 	 * so use the equivalent hint instruction.
18281a08ccSDimitris Papastamos 	 */
19*40daecc1SAntonio Nino Diaz 	__asm__ volatile("hint #17");
20*40daecc1SAntonio Nino Diaz }
21281a08ccSDimitris Papastamos 
22*40daecc1SAntonio Nino Diaz bool spe_supported(void)
23281a08ccSDimitris Papastamos {
24281a08ccSDimitris Papastamos 	uint64_t features;
25281a08ccSDimitris Papastamos 
26281a08ccSDimitris Papastamos 	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
27*40daecc1SAntonio Nino Diaz 	return (features & ID_AA64DFR0_PMS_MASK) == 1U;
282ff8fbf3SDimitris Papastamos }
292ff8fbf3SDimitris Papastamos 
30*40daecc1SAntonio Nino Diaz void spe_enable(bool el2_unused)
312ff8fbf3SDimitris Papastamos {
32281a08ccSDimitris Papastamos 	uint64_t v;
33281a08ccSDimitris Papastamos 
34*40daecc1SAntonio Nino Diaz 	if (!spe_supported())
352ff8fbf3SDimitris Papastamos 		return;
362ff8fbf3SDimitris Papastamos 
37281a08ccSDimitris Papastamos 	if (el2_unused) {
38281a08ccSDimitris Papastamos 		/*
39281a08ccSDimitris Papastamos 		 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
40281a08ccSDimitris Papastamos 		 * profiling controls to EL2.
41281a08ccSDimitris Papastamos 		 *
42281a08ccSDimitris Papastamos 		 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
43281a08ccSDimitris Papastamos 		 * state. Accesses to profiling buffer controls at
44281a08ccSDimitris Papastamos 		 * Non-secure EL1 are not trapped to EL2.
45281a08ccSDimitris Papastamos 		 */
46281a08ccSDimitris Papastamos 		v = read_mdcr_el2();
47281a08ccSDimitris Papastamos 		v &= ~MDCR_EL2_TPMS;
48281a08ccSDimitris Papastamos 		v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
49281a08ccSDimitris Papastamos 		write_mdcr_el2(v);
50281a08ccSDimitris Papastamos 	}
51281a08ccSDimitris Papastamos 
52281a08ccSDimitris Papastamos 	/*
53281a08ccSDimitris Papastamos 	 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
54281a08ccSDimitris Papastamos 	 * and disabled in secure state. Accesses to SPE registers at
55281a08ccSDimitris Papastamos 	 * S-EL1 generate trap exceptions to EL3.
56281a08ccSDimitris Papastamos 	 */
57281a08ccSDimitris Papastamos 	v = read_mdcr_el3();
58281a08ccSDimitris Papastamos 	v |= MDCR_NSPB(MDCR_NSPB_EL1);
59281a08ccSDimitris Papastamos 	write_mdcr_el3(v);
60281a08ccSDimitris Papastamos }
61281a08ccSDimitris Papastamos 
62281a08ccSDimitris Papastamos void spe_disable(void)
63281a08ccSDimitris Papastamos {
64281a08ccSDimitris Papastamos 	uint64_t v;
65281a08ccSDimitris Papastamos 
66*40daecc1SAntonio Nino Diaz 	if (!spe_supported())
672ff8fbf3SDimitris Papastamos 		return;
682ff8fbf3SDimitris Papastamos 
69281a08ccSDimitris Papastamos 	/* Drain buffered data */
70281a08ccSDimitris Papastamos 	psb_csync();
71281a08ccSDimitris Papastamos 	dsbnsh();
72281a08ccSDimitris Papastamos 
73281a08ccSDimitris Papastamos 	/* Disable profiling buffer */
74281a08ccSDimitris Papastamos 	v = read_pmblimitr_el1();
75281a08ccSDimitris Papastamos 	v &= ~(1ULL << 0);
76281a08ccSDimitris Papastamos 	write_pmblimitr_el1(v);
77281a08ccSDimitris Papastamos 	isb();
78281a08ccSDimitris Papastamos }
79281a08ccSDimitris Papastamos 
80281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg)
81281a08ccSDimitris Papastamos {
82*40daecc1SAntonio Nino Diaz 	if (!spe_supported())
832ff8fbf3SDimitris Papastamos 		return (void *)-1;
84281a08ccSDimitris Papastamos 
85281a08ccSDimitris Papastamos 	/* Drain buffered data */
86281a08ccSDimitris Papastamos 	psb_csync();
87281a08ccSDimitris Papastamos 	dsbnsh();
88*40daecc1SAntonio Nino Diaz 
89*40daecc1SAntonio Nino Diaz 	return (void *)0;
90281a08ccSDimitris Papastamos }
91281a08ccSDimitris Papastamos 
92281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
93