• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <string.h>
8 #include <common/debug.h>
9 #include <lib/mmio.h>
10 #include <smccc_helpers.h>
11 
12 #include <emi_mpu.h>
13 #include <lib/mtk_init/mtk_init.h>
14 #include <mtk_sip_svc.h>
15 
16 #if ENABLE_EMI_MPU_SW_LOCK
17 static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
18 #endif
19 
20 #define EMI_MPU_START_MASK		(0x00FFFFFF)
21 #define EMI_MPU_END_MASK		(0x00FFFFFF)
22 #define EMI_MPU_APC_SW_LOCK_MASK	(0x00FFFFFF)
23 #define EMI_MPU_APC_HW_LOCK_MASK	(0x80FFFFFF)
24 
_emi_mpu_set_protection(unsigned int start,unsigned int end,unsigned int apc)25 static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
26 					unsigned int apc)
27 {
28 	unsigned int dgroup;
29 	unsigned int region;
30 
31 	region = (start >> 24) & 0xFF;
32 	start &= EMI_MPU_START_MASK;
33 	dgroup = (end >> 24) & 0xFF;
34 	end &= EMI_MPU_END_MASK;
35 
36 	if  ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
37 		WARN("invalid region, domain\n");
38 		return -1;
39 	}
40 
41 #if ENABLE_EMI_MPU_SW_LOCK
42 	if (region_lock_state[region] == LOCK) {
43 		WARN("invalid region\n");
44 		return -1;
45 	}
46 
47 	if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
48 		region_lock_state[region] = LOCK;
49 	}
50 
51 	apc &= EMI_MPU_APC_SW_LOCK_MASK;
52 #else
53 	apc &= EMI_MPU_APC_HW_LOCK_MASK;
54 #endif
55 
56 	if ((start >= DRAM_OFFSET) && (end >= start)) {
57 		start -= DRAM_OFFSET;
58 		end -= DRAM_OFFSET;
59 	} else {
60 		WARN("invalid range\n");
61 		return -1;
62 	}
63 
64 	mmio_write_32(EMI_MPU_SA(region), start);
65 	mmio_write_32(EMI_MPU_EA(region), end);
66 	mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
67 
68 #if defined(SUB_EMI_MPU_BASE)
69 	mmio_write_32(SUB_EMI_MPU_SA(region), start);
70 	mmio_write_32(SUB_EMI_MPU_EA(region), end);
71 	mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
72 #endif
73 	return 0;
74 }
75 
emi_mpu_clear_protection(unsigned int region)76 int emi_mpu_clear_protection(unsigned int region)
77 {
78 	unsigned int dgroup;
79 
80 	if (region >= EMI_MPU_REGION_NUM) {
81 		WARN("invalid region number\n");
82 		return -1;
83 	}
84 
85 #if ENABLE_EMI_MPU_SW_LOCK
86 	if (region_lock_state[region] == LOCK) {
87 		WARN("SW:region is locked\n");
88 		return -1;
89 	}
90 #endif
91 	if (mmio_read_32(EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
92 		WARN("HW:EMI-MPU region is locked\n");
93 		return -1;
94 	}
95 
96 #if defined(SUB_EMI_MPU_BASE)
97 	if (mmio_read_32(SUB_EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
98 		WARN("HW:SUB EMI-MPU region is locked\n");
99 		return -1;
100 	}
101 #endif
102 
103 	for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
104 		mmio_write_32(EMI_MPU_APC(region, dgroup), 0x0);
105 
106 	mmio_write_32(EMI_MPU_SA(region), 0x0);
107 	mmio_write_32(EMI_MPU_EA(region), 0x0);
108 
109 #if defined(SUB_EMI_MPU_BASE)
110 	for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
111 		mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), 0x0);
112 
113 	mmio_write_32(SUB_EMI_MPU_SA(region), 0);
114 	mmio_write_32(SUB_EMI_MPU_EA(region), 0);
115 #endif
116 	return 0;
117 }
118 
119 
dump_emi_mpu_regions(void)120 static void dump_emi_mpu_regions(void)
121 {
122 	int region, i;
123 
124 	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
125 	for (region = 0; region < 8; ++region) {
126 		INFO("region %d:\n", region);
127 		INFO("\tsa: 0x%x, ea: 0x%x\n",
128 		     mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
129 
130 		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
131 			INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
132 		}
133 	}
134 }
135 
emi_mpu_set_protection(struct emi_region_info_t * region_info)136 int emi_mpu_set_protection(struct emi_region_info_t *region_info)
137 {
138 	unsigned int start, end;
139 	int i;
140 
141 	if (region_info->region >= EMI_MPU_REGION_NUM) {
142 		WARN("invalid region\n");
143 		return -1;
144 	}
145 
146 	start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
147 		(region_info->region << 24);
148 
149 	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
150 		end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
151 
152 		if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
153 			WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
154 			     start, end, region_info->apc[i]);
155 		}
156 	}
157 
158 	return 0;
159 }
160 
mtk_emi_mpu_sip_handler(u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * handle,struct smccc_res * smccc_ret)161 u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2,
162 				     u_register_t x3, u_register_t x4,
163 				     void *handle, struct smccc_res *smccc_ret)
164 {
165 	return (u_register_t) emi_mpu_optee_handler(x1, x2, x3);
166 }
167 DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler);
168 
emi_mpu_init(void)169 int emi_mpu_init(void)
170 {
171 	INFO("[%s] emi mpu initialization\n", __func__);
172 
173 	set_emi_mpu_regions();
174 	dump_emi_mpu_regions();
175 
176 	return 0;
177 }
178 MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
179