1 /*
2  * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdbool.h>
8 
9 #include <common/debug.h>
10 #include <lib/mpmm/mpmm.h>
11 
12 #include <plat/common/platform.h>
13 
14 #if ENABLE_MPMM_FCONF
15 #	include <lib/fconf/fconf.h>
16 #	include <lib/fconf/fconf_mpmm_getter.h>
17 #endif
18 
read_cpuppmcr_el3_mpmmpinctl(void)19 static uint64_t read_cpuppmcr_el3_mpmmpinctl(void)
20 {
21 	return (read_cpuppmcr_el3() >> CPUPPMCR_EL3_MPMMPINCTL_SHIFT) &
22 		CPUPPMCR_EL3_MPMMPINCTL_MASK;
23 }
24 
write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en)25 static void write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en)
26 {
27 	uint64_t value = read_cpumpmmcr_el3();
28 
29 	value &= ~(CPUMPMMCR_EL3_MPMM_EN_MASK << CPUMPMMCR_EL3_MPMM_EN_SHIFT);
30 	value |= (mpmm_en & CPUMPMMCR_EL3_MPMM_EN_MASK) <<
31 		CPUMPMMCR_EL3_MPMM_EN_SHIFT;
32 
33 	write_cpumpmmcr_el3(value);
34 }
35 
mpmm_supported(void)36 static bool mpmm_supported(void)
37 {
38 	bool supported = false;
39 	const struct mpmm_topology *topology;
40 
41 #if ENABLE_MPMM_FCONF
42 	topology = FCONF_GET_PROPERTY(mpmm, config, topology);
43 #else
44 	topology = plat_mpmm_topology();
45 #endif /* ENABLE_MPMM_FCONF */
46 
47 	/*
48 	 * For the current core firstly try to find out if the platform
49 	 * configuration has claimed support for MPMM, then make sure that MPMM
50 	 * is controllable through the system registers.
51 	 */
52 
53 	if (topology != NULL) {
54 		unsigned int core_pos = plat_my_core_pos();
55 
56 		supported = topology->cores[core_pos].supported &&
57 			(read_cpuppmcr_el3_mpmmpinctl() == 0U);
58 	} else {
59 		ERROR("MPMM: failed to generate MPMM topology\n");
60 	}
61 
62 	return supported;
63 }
64 
65 /* Defaults to false */
66 static bool mpmm_disable_for_errata;
67 
mpmm_enable(void)68 void mpmm_enable(void)
69 {
70 	if (mpmm_supported()) {
71 		if (mpmm_disable_for_errata) {
72 			WARN("MPMM: disabled by errata workaround\n");
73 			return;
74 		}
75 		write_cpumpmmcr_el3_mpmm_en(1U);
76 	}
77 }
78 
79 /*
80  * This function is called from assembly code very early in BL31 so it must be
81  * small and simple.
82  */
mpmm_errata_disable(void)83 void mpmm_errata_disable(void)
84 {
85 	mpmm_disable_for_errata = true;
86 }
87