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