1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <string.h> 8*91f16700Schasinglulu #include <common/debug.h> 9*91f16700Schasinglulu #include <lib/mmio.h> 10*91f16700Schasinglulu #include <smccc_helpers.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <emi_mpu.h> 13*91f16700Schasinglulu #include <lib/mtk_init/mtk_init.h> 14*91f16700Schasinglulu #include <mtk_sip_svc.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu #if ENABLE_EMI_MPU_SW_LOCK 17*91f16700Schasinglulu static unsigned char region_lock_state[EMI_MPU_REGION_NUM]; 18*91f16700Schasinglulu #endif 19*91f16700Schasinglulu 20*91f16700Schasinglulu #define EMI_MPU_START_MASK (0x00FFFFFF) 21*91f16700Schasinglulu #define EMI_MPU_END_MASK (0x00FFFFFF) 22*91f16700Schasinglulu #define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF) 23*91f16700Schasinglulu #define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF) 24*91f16700Schasinglulu 25*91f16700Schasinglulu static int _emi_mpu_set_protection(unsigned int start, unsigned int end, 26*91f16700Schasinglulu unsigned int apc) 27*91f16700Schasinglulu { 28*91f16700Schasinglulu unsigned int dgroup; 29*91f16700Schasinglulu unsigned int region; 30*91f16700Schasinglulu 31*91f16700Schasinglulu region = (start >> 24) & 0xFF; 32*91f16700Schasinglulu start &= EMI_MPU_START_MASK; 33*91f16700Schasinglulu dgroup = (end >> 24) & 0xFF; 34*91f16700Schasinglulu end &= EMI_MPU_END_MASK; 35*91f16700Schasinglulu 36*91f16700Schasinglulu if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) { 37*91f16700Schasinglulu WARN("invalid region, domain\n"); 38*91f16700Schasinglulu return -1; 39*91f16700Schasinglulu } 40*91f16700Schasinglulu 41*91f16700Schasinglulu #if ENABLE_EMI_MPU_SW_LOCK 42*91f16700Schasinglulu if (region_lock_state[region] == 1) { 43*91f16700Schasinglulu WARN("invalid region\n"); 44*91f16700Schasinglulu return -1; 45*91f16700Schasinglulu } 46*91f16700Schasinglulu 47*91f16700Schasinglulu if ((dgroup == 0) && ((apc >> 31) & 0x1)) { 48*91f16700Schasinglulu region_lock_state[region] = 1; 49*91f16700Schasinglulu } 50*91f16700Schasinglulu 51*91f16700Schasinglulu apc &= EMI_MPU_APC_SW_LOCK_MASK; 52*91f16700Schasinglulu #else 53*91f16700Schasinglulu apc &= EMI_MPU_APC_HW_LOCK_MASK; 54*91f16700Schasinglulu #endif 55*91f16700Schasinglulu 56*91f16700Schasinglulu if ((start >= DRAM_OFFSET) && (end >= start)) { 57*91f16700Schasinglulu start -= DRAM_OFFSET; 58*91f16700Schasinglulu end -= DRAM_OFFSET; 59*91f16700Schasinglulu } else { 60*91f16700Schasinglulu WARN("invalid range\n"); 61*91f16700Schasinglulu return -1; 62*91f16700Schasinglulu } 63*91f16700Schasinglulu 64*91f16700Schasinglulu mmio_write_32(EMI_MPU_SA(region), start); 65*91f16700Schasinglulu mmio_write_32(EMI_MPU_EA(region), end); 66*91f16700Schasinglulu mmio_write_32(EMI_MPU_APC(region, dgroup), apc); 67*91f16700Schasinglulu 68*91f16700Schasinglulu #if defined(SUB_EMI_MPU_BASE) 69*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_SA(region), start); 70*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_EA(region), end); 71*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc); 72*91f16700Schasinglulu #endif 73*91f16700Schasinglulu return 0; 74*91f16700Schasinglulu } 75*91f16700Schasinglulu 76*91f16700Schasinglulu static void dump_emi_mpu_regions(void) 77*91f16700Schasinglulu { 78*91f16700Schasinglulu int region, i; 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */ 81*91f16700Schasinglulu for (region = 0; region < 8; ++region) { 82*91f16700Schasinglulu INFO("region %d:\n", region); 83*91f16700Schasinglulu INFO("\tsa: 0x%x, ea: 0x%x\n", 84*91f16700Schasinglulu mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region))); 85*91f16700Schasinglulu 86*91f16700Schasinglulu for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) { 87*91f16700Schasinglulu INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i))); 88*91f16700Schasinglulu } 89*91f16700Schasinglulu } 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu int emi_mpu_set_protection(struct emi_region_info_t *region_info) 93*91f16700Schasinglulu { 94*91f16700Schasinglulu unsigned int start, end; 95*91f16700Schasinglulu int i; 96*91f16700Schasinglulu 97*91f16700Schasinglulu if (region_info->region >= EMI_MPU_REGION_NUM) { 98*91f16700Schasinglulu WARN("invalid region\n"); 99*91f16700Schasinglulu return -1; 100*91f16700Schasinglulu } 101*91f16700Schasinglulu 102*91f16700Schasinglulu start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) | 103*91f16700Schasinglulu (region_info->region << 24); 104*91f16700Schasinglulu 105*91f16700Schasinglulu for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) { 106*91f16700Schasinglulu end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24); 107*91f16700Schasinglulu 108*91f16700Schasinglulu if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) { 109*91f16700Schasinglulu WARN("Failed to set emi mpu protection(%d, %d, %d)\n", 110*91f16700Schasinglulu start, end, region_info->apc[i]); 111*91f16700Schasinglulu } 112*91f16700Schasinglulu } 113*91f16700Schasinglulu 114*91f16700Schasinglulu return 0; 115*91f16700Schasinglulu } 116*91f16700Schasinglulu 117*91f16700Schasinglulu u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2, 118*91f16700Schasinglulu u_register_t x3, u_register_t x4, 119*91f16700Schasinglulu void *handle, struct smccc_res *smccc_ret) 120*91f16700Schasinglulu { 121*91f16700Schasinglulu return (u_register_t) emi_mpu_optee_handler(x1, x2, x3); 122*91f16700Schasinglulu } 123*91f16700Schasinglulu DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler); 124*91f16700Schasinglulu 125*91f16700Schasinglulu int emi_mpu_init(void) 126*91f16700Schasinglulu { 127*91f16700Schasinglulu INFO("[%s] emi mpu initialization\n", __func__); 128*91f16700Schasinglulu 129*91f16700Schasinglulu set_emi_mpu_regions(); 130*91f16700Schasinglulu dump_emi_mpu_regions(); 131*91f16700Schasinglulu 132*91f16700Schasinglulu return 0; 133*91f16700Schasinglulu } 134*91f16700Schasinglulu MTK_PLAT_SETUP_0_INIT(emi_mpu_init); 135