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] == 1) {
43 		WARN("invalid region\n");
44 		return -1;
45 	}
46 
47 	if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
48 		region_lock_state[region] = 1;
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 
dump_emi_mpu_regions(void)76 static void dump_emi_mpu_regions(void)
77 {
78 	int region, i;
79 
80 	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
81 	for (region = 0; region < 8; ++region) {
82 		INFO("region %d:\n", region);
83 		INFO("\tsa: 0x%x, ea: 0x%x\n",
84 		     mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
85 
86 		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
87 			INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
88 		}
89 	}
90 }
91 
emi_mpu_set_protection(struct emi_region_info_t * region_info)92 int emi_mpu_set_protection(struct emi_region_info_t *region_info)
93 {
94 	unsigned int start, end;
95 	int i;
96 
97 	if (region_info->region >= EMI_MPU_REGION_NUM) {
98 		WARN("invalid region\n");
99 		return -1;
100 	}
101 
102 	start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
103 		(region_info->region << 24);
104 
105 	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
106 		end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
107 
108 		if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
109 			WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
110 			     start, end, region_info->apc[i]);
111 		}
112 	}
113 
114 	return 0;
115 }
116 
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)117 u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2,
118 				     u_register_t x3, u_register_t x4,
119 				     void *handle, struct smccc_res *smccc_ret)
120 {
121 	return (u_register_t) emi_mpu_optee_handler(x1, x2, x3);
122 }
123 DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler);
124 
emi_mpu_init(void)125 int emi_mpu_init(void)
126 {
127 	INFO("[%s] emi mpu initialization\n", __func__);
128 
129 	set_emi_mpu_regions();
130 	dump_emi_mpu_regions();
131 
132 	return 0;
133 }
134 MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
135