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 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] == LOCK) { 43 WARN("invalid region\n"); 44 return -1; 45 } 46 47 if ((dgroup == 0) && ((apc >> 31) & 0x1)) { 48 region_lock_state[region] = LOCK; 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 76 int emi_mpu_clear_protection(unsigned int region) 77 { 78 unsigned int dgroup; 79 80 if (region >= EMI_MPU_REGION_NUM) { 81 WARN("invalid region number\n"); 82 return -1; 83 } 84 85 #if ENABLE_EMI_MPU_SW_LOCK 86 if (region_lock_state[region] == LOCK) { 87 WARN("SW:region is locked\n"); 88 return -1; 89 } 90 #endif 91 if (mmio_read_32(EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) { 92 WARN("HW:EMI-MPU region is locked\n"); 93 return -1; 94 } 95 96 #if defined(SUB_EMI_MPU_BASE) 97 if (mmio_read_32(SUB_EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) { 98 WARN("HW:SUB EMI-MPU region is locked\n"); 99 return -1; 100 } 101 #endif 102 103 for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++) 104 mmio_write_32(EMI_MPU_APC(region, dgroup), 0x0); 105 106 mmio_write_32(EMI_MPU_SA(region), 0x0); 107 mmio_write_32(EMI_MPU_EA(region), 0x0); 108 109 #if defined(SUB_EMI_MPU_BASE) 110 for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++) 111 mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), 0x0); 112 113 mmio_write_32(SUB_EMI_MPU_SA(region), 0); 114 mmio_write_32(SUB_EMI_MPU_EA(region), 0); 115 #endif 116 return 0; 117 } 118 119 120 static void dump_emi_mpu_regions(void) 121 { 122 int region, i; 123 124 /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */ 125 for (region = 0; region < 8; ++region) { 126 INFO("region %d:\n", region); 127 INFO("\tsa: 0x%x, ea: 0x%x\n", 128 mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region))); 129 130 for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) { 131 INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i))); 132 } 133 } 134 } 135 136 int emi_mpu_set_protection(struct emi_region_info_t *region_info) 137 { 138 unsigned int start, end; 139 int i; 140 141 if (region_info->region >= EMI_MPU_REGION_NUM) { 142 WARN("invalid region\n"); 143 return -1; 144 } 145 146 start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) | 147 (region_info->region << 24); 148 149 for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) { 150 end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24); 151 152 if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) { 153 WARN("Failed to set emi mpu protection(%d, %d, %d)\n", 154 start, end, region_info->apc[i]); 155 } 156 } 157 158 return 0; 159 } 160 161 u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2, 162 u_register_t x3, u_register_t x4, 163 void *handle, struct smccc_res *smccc_ret) 164 { 165 return (u_register_t) emi_mpu_optee_handler(x1, x2, x3); 166 } 167 DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler); 168 169 int emi_mpu_init(void) 170 { 171 INFO("[%s] emi mpu initialization\n", __func__); 172 173 set_emi_mpu_regions(); 174 dump_emi_mpu_regions(); 175 176 return 0; 177 } 178 MTK_PLAT_SETUP_0_INIT(emi_mpu_init); 179