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] == 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 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 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 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 int ret; 122 123 ret = emi_mpu_optee_handler(x1, x2, x3); 124 SMC_RET2(handle, ret, 0U); 125 126 return 0; 127 } 128 DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler); 129 130 int emi_mpu_init(void) 131 { 132 INFO("[%s] emi mpu initialization\n", __func__); 133 134 set_emi_mpu_regions(); 135 dump_emi_mpu_regions(); 136 137 return 0; 138 } 139 MTK_PLAT_SETUP_0_INIT(emi_mpu_init); 140