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