1 /*
2  * Copyright (c) 2021-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 <emi_mpu.h>
11 #include <mtk_sip_svc.h>
12 
13 #if ENABLE_EMI_MPU_SW_LOCK
14 static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
15 #endif
16 
17 #define EMI_MPU_START_MASK		(0x00FFFFFF)
18 #define EMI_MPU_END_MASK		(0x00FFFFFF)
19 #define EMI_MPU_APC_SW_LOCK_MASK	(0x00FFFFFF)
20 #define EMI_MPU_APC_HW_LOCK_MASK	(0x80FFFFFF)
21 #define MPU_PHYSICAL_ADDR_SHIFT_BITS	(16)
22 
_emi_mpu_set_protection(unsigned int start,unsigned int end,unsigned int apc)23 static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
24 					unsigned int apc)
25 {
26 	unsigned int dgroup;
27 	unsigned int region;
28 
29 	region = (start >> 24) & 0xFF;
30 	start &= EMI_MPU_START_MASK;
31 	dgroup = (end >> 24) & 0xFF;
32 	end &= EMI_MPU_END_MASK;
33 
34 	if  ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
35 		WARN("invalid region, domain\n");
36 		return -1;
37 	}
38 
39 #if ENABLE_EMI_MPU_SW_LOCK
40 	if (region_lock_state[region] == 1) {
41 		WARN("invalid region\n");
42 		return -1;
43 	}
44 
45 	if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
46 		region_lock_state[region] = 1;
47 	}
48 
49 	apc &= EMI_MPU_APC_SW_LOCK_MASK;
50 #else
51 	apc &= EMI_MPU_APC_HW_LOCK_MASK;
52 #endif
53 
54 	if ((start >= DRAM_OFFSET) && (end >= start)) {
55 		start -= DRAM_OFFSET;
56 		end -= DRAM_OFFSET;
57 	} else {
58 		WARN("invalid range\n");
59 		return -1;
60 	}
61 
62 	mmio_write_32(EMI_MPU_SA(region), start);
63 	mmio_write_32(EMI_MPU_EA(region), end);
64 	mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
65 
66 #if defined(SUB_EMI_MPU_BASE)
67 	mmio_write_32(SUB_EMI_MPU_SA(region), start);
68 	mmio_write_32(SUB_EMI_MPU_EA(region), end);
69 	mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
70 #endif
71 	return 1;
72 }
73 
emi_mpu_set_protection(struct emi_region_info_t * region_info)74 int emi_mpu_set_protection(struct emi_region_info_t *region_info)
75 {
76 	unsigned int start, end;
77 	int i;
78 
79 	if (region_info->region >= EMI_MPU_REGION_NUM) {
80 		WARN("invalid region\n");
81 		return -1;
82 	}
83 
84 	start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
85 		(region_info->region << 24);
86 
87 	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
88 		end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) |
89 			(i << 24);
90 		_emi_mpu_set_protection(start, end, region_info->apc[i]);
91 	}
92 
93 	return 0;
94 }
95 
dump_emi_mpu_regions(void)96 void dump_emi_mpu_regions(void)
97 {
98 	unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea;
99 
100 	int region, i;
101 
102 	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
103 	for (region = 0; region < 8; ++region) {
104 		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i)
105 			apc[i] = mmio_read_32(EMI_MPU_APC(region, i));
106 		sa = mmio_read_32(EMI_MPU_SA(region));
107 		ea = mmio_read_32(EMI_MPU_EA(region));
108 
109 		INFO("region %d:\n", region);
110 		INFO("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n",
111 		     sa, ea, apc[0], apc[1]);
112 	}
113 }
114 
emi_mpu_init(void)115 void emi_mpu_init(void)
116 {
117 	struct emi_region_info_t region_info;
118 
119 	/* SCP DRAM */
120 	region_info.start = 0x50000000ULL;
121 	region_info.end = 0x51400000ULL;
122 	region_info.region = 2;
123 	SET_ACCESS_PERMISSION(region_info.apc, 1,
124 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
125 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
126 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
127 			      NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
128 	emi_mpu_set_protection(&region_info);
129 
130 	/* DSP protect address */
131 	region_info.start = 0x60000000ULL;	/* dram base addr */
132 	region_info.end = 0x610FFFFFULL;
133 	region_info.region = 3;
134 	SET_ACCESS_PERMISSION(region_info.apc, 1,
135 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
136 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
137 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
138 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
139 	emi_mpu_set_protection(&region_info);
140 
141 	/* Forbidden All */
142 	region_info.start = 0x40000000ULL;	/* dram base addr */
143 	region_info.end = 0x1FFFF0000ULL;
144 	region_info.region = 5;
145 	SET_ACCESS_PERMISSION(region_info.apc, 1,
146 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
147 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
148 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
149 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
150 	emi_mpu_set_protection(&region_info);
151 
152 	dump_emi_mpu_regions();
153 }
154 
get_decoded_phys_addr(uint64_t addr)155 static inline uint64_t get_decoded_phys_addr(uint64_t addr)
156 {
157 	return (addr << MPU_PHYSICAL_ADDR_SHIFT_BITS);
158 }
159 
get_decoded_zone_id(uint32_t info)160 static inline uint32_t get_decoded_zone_id(uint32_t info)
161 {
162 	return ((info & 0xFFFF0000) >> MPU_PHYSICAL_ADDR_SHIFT_BITS);
163 }
164 
emi_mpu_sip_handler(uint64_t encoded_addr,uint64_t zone_size,uint64_t zone_info)165 int32_t emi_mpu_sip_handler(uint64_t encoded_addr, uint64_t zone_size, uint64_t zone_info)
166 {
167 	uint64_t phys_addr = get_decoded_phys_addr(encoded_addr);
168 	struct emi_region_info_t region_info;
169 	enum MPU_REQ_ORIGIN_ZONE_ID zone_id = get_decoded_zone_id(zone_info);
170 
171 	INFO("encoded_addr = 0x%lx, zone_size = 0x%lx, zone_info = 0x%lx\n",
172 	     encoded_addr, zone_size, zone_info);
173 
174 	if (zone_id != MPU_REQ_ORIGIN_TEE_ZONE_SVP) {
175 		ERROR("Invalid param %s, %d\n", __func__, __LINE__);
176 		return MTK_SIP_E_INVALID_PARAM;
177 	}
178 
179 	/* SVP DRAM */
180 	region_info.start = phys_addr;
181 	region_info.end = phys_addr + zone_size;
182 	region_info.region = 4;
183 	SET_ACCESS_PERMISSION(region_info.apc, 1,
184 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
185 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
186 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
187 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, SEC_RW);
188 
189 	emi_mpu_set_protection(&region_info);
190 
191 	return 0;
192 }
193