1 /*
2  * Copyright (c) 2022, 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 <lib/mtk_init/mtk_init.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 
_emi_mpu_set_protection(unsigned int start,unsigned int end,unsigned int apc)22 static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
23 					unsigned int apc)
24 {
25 	unsigned int dgroup;
26 	unsigned int region;
27 
28 	region = (start >> 24) & 0xFF;
29 	start &= EMI_MPU_START_MASK;
30 	dgroup = (end >> 24) & 0xFF;
31 	end &= EMI_MPU_END_MASK;
32 
33 	if  ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
34 		WARN("invalid region, domain\n");
35 		return -1;
36 	}
37 
38 #if ENABLE_EMI_MPU_SW_LOCK
39 	if (region_lock_state[region] == 1) {
40 		WARN("invalid region\n");
41 		return -1;
42 	}
43 
44 	if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
45 		region_lock_state[region] = 1;
46 	}
47 
48 	apc &= EMI_MPU_APC_SW_LOCK_MASK;
49 #else
50 	apc &= EMI_MPU_APC_HW_LOCK_MASK;
51 #endif
52 
53 	if ((start >= DRAM_OFFSET) && (end >= start)) {
54 		start -= DRAM_OFFSET;
55 		end -= DRAM_OFFSET;
56 	} else {
57 		WARN("invalid range\n");
58 		return -1;
59 	}
60 
61 	mmio_write_32(EMI_MPU_SA(region), start);
62 	mmio_write_32(EMI_MPU_EA(region), end);
63 	mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
64 
65 #if defined(SUB_EMI_MPU_BASE)
66 	mmio_write_32(SUB_EMI_MPU_SA(region), start);
67 	mmio_write_32(SUB_EMI_MPU_EA(region), end);
68 	mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
69 #endif
70 	return 0;
71 }
72 
dump_emi_mpu_regions(void)73 static void dump_emi_mpu_regions(void)
74 {
75 	int region, i;
76 
77 	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
78 	for (region = 0; region < 8; ++region) {
79 		INFO("region %d:\n", region);
80 		INFO("\tsa: 0x%x, ea: 0x%x\n",
81 		     mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
82 
83 		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
84 			INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
85 		}
86 	}
87 }
88 
emi_mpu_set_protection(struct emi_region_info_t * region_info)89 int emi_mpu_set_protection(struct emi_region_info_t *region_info)
90 {
91 	unsigned int start, end;
92 	int i;
93 
94 	if (region_info->region >= EMI_MPU_REGION_NUM) {
95 		WARN("invalid region\n");
96 		return -1;
97 	}
98 
99 	start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
100 		(region_info->region << 24);
101 
102 	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
103 		end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
104 
105 		if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
106 			WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
107 			     start, end, region_info->apc[i]);
108 		}
109 	}
110 
111 	return 0;
112 }
113 
emi_mpu_init(void)114 int emi_mpu_init(void)
115 {
116 	INFO("[%s] emi mpu initialization\n", __func__);
117 
118 	set_emi_mpu_regions();
119 	dump_emi_mpu_regions();
120 
121 	return 0;
122 }
123 MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
124