1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021-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 <emi_mpu.h> 11*91f16700Schasinglulu #include <mtk_sip_svc.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #if ENABLE_EMI_MPU_SW_LOCK 14*91f16700Schasinglulu static unsigned char region_lock_state[EMI_MPU_REGION_NUM]; 15*91f16700Schasinglulu #endif 16*91f16700Schasinglulu 17*91f16700Schasinglulu #define EMI_MPU_START_MASK (0x00FFFFFF) 18*91f16700Schasinglulu #define EMI_MPU_END_MASK (0x00FFFFFF) 19*91f16700Schasinglulu #define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF) 20*91f16700Schasinglulu #define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF) 21*91f16700Schasinglulu #define MPU_PHYSICAL_ADDR_SHIFT_BITS (16) 22*91f16700Schasinglulu 23*91f16700Schasinglulu static int _emi_mpu_set_protection(unsigned int start, unsigned int end, 24*91f16700Schasinglulu unsigned int apc) 25*91f16700Schasinglulu { 26*91f16700Schasinglulu unsigned int dgroup; 27*91f16700Schasinglulu unsigned int region; 28*91f16700Schasinglulu 29*91f16700Schasinglulu region = (start >> 24) & 0xFF; 30*91f16700Schasinglulu start &= EMI_MPU_START_MASK; 31*91f16700Schasinglulu dgroup = (end >> 24) & 0xFF; 32*91f16700Schasinglulu end &= EMI_MPU_END_MASK; 33*91f16700Schasinglulu 34*91f16700Schasinglulu if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) { 35*91f16700Schasinglulu WARN("invalid region, domain\n"); 36*91f16700Schasinglulu return -1; 37*91f16700Schasinglulu } 38*91f16700Schasinglulu 39*91f16700Schasinglulu #if ENABLE_EMI_MPU_SW_LOCK 40*91f16700Schasinglulu if (region_lock_state[region] == 1) { 41*91f16700Schasinglulu WARN("invalid region\n"); 42*91f16700Schasinglulu return -1; 43*91f16700Schasinglulu } 44*91f16700Schasinglulu 45*91f16700Schasinglulu if ((dgroup == 0) && ((apc >> 31) & 0x1)) { 46*91f16700Schasinglulu region_lock_state[region] = 1; 47*91f16700Schasinglulu } 48*91f16700Schasinglulu 49*91f16700Schasinglulu apc &= EMI_MPU_APC_SW_LOCK_MASK; 50*91f16700Schasinglulu #else 51*91f16700Schasinglulu apc &= EMI_MPU_APC_HW_LOCK_MASK; 52*91f16700Schasinglulu #endif 53*91f16700Schasinglulu 54*91f16700Schasinglulu if ((start >= DRAM_OFFSET) && (end >= start)) { 55*91f16700Schasinglulu start -= DRAM_OFFSET; 56*91f16700Schasinglulu end -= DRAM_OFFSET; 57*91f16700Schasinglulu } else { 58*91f16700Schasinglulu WARN("invalid range\n"); 59*91f16700Schasinglulu return -1; 60*91f16700Schasinglulu } 61*91f16700Schasinglulu 62*91f16700Schasinglulu mmio_write_32(EMI_MPU_SA(region), start); 63*91f16700Schasinglulu mmio_write_32(EMI_MPU_EA(region), end); 64*91f16700Schasinglulu mmio_write_32(EMI_MPU_APC(region, dgroup), apc); 65*91f16700Schasinglulu 66*91f16700Schasinglulu #if defined(SUB_EMI_MPU_BASE) 67*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_SA(region), start); 68*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_EA(region), end); 69*91f16700Schasinglulu mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc); 70*91f16700Schasinglulu #endif 71*91f16700Schasinglulu return 1; 72*91f16700Schasinglulu } 73*91f16700Schasinglulu 74*91f16700Schasinglulu int emi_mpu_set_protection(struct emi_region_info_t *region_info) 75*91f16700Schasinglulu { 76*91f16700Schasinglulu unsigned int start, end; 77*91f16700Schasinglulu int i; 78*91f16700Schasinglulu 79*91f16700Schasinglulu if (region_info->region >= EMI_MPU_REGION_NUM) { 80*91f16700Schasinglulu WARN("invalid region\n"); 81*91f16700Schasinglulu return -1; 82*91f16700Schasinglulu } 83*91f16700Schasinglulu 84*91f16700Schasinglulu start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) | 85*91f16700Schasinglulu (region_info->region << 24); 86*91f16700Schasinglulu 87*91f16700Schasinglulu for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) { 88*91f16700Schasinglulu end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | 89*91f16700Schasinglulu (i << 24); 90*91f16700Schasinglulu _emi_mpu_set_protection(start, end, region_info->apc[i]); 91*91f16700Schasinglulu } 92*91f16700Schasinglulu 93*91f16700Schasinglulu return 0; 94*91f16700Schasinglulu } 95*91f16700Schasinglulu 96*91f16700Schasinglulu void dump_emi_mpu_regions(void) 97*91f16700Schasinglulu { 98*91f16700Schasinglulu unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea; 99*91f16700Schasinglulu 100*91f16700Schasinglulu int region, i; 101*91f16700Schasinglulu 102*91f16700Schasinglulu /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */ 103*91f16700Schasinglulu for (region = 0; region < 8; ++region) { 104*91f16700Schasinglulu for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) 105*91f16700Schasinglulu apc[i] = mmio_read_32(EMI_MPU_APC(region, i)); 106*91f16700Schasinglulu sa = mmio_read_32(EMI_MPU_SA(region)); 107*91f16700Schasinglulu ea = mmio_read_32(EMI_MPU_EA(region)); 108*91f16700Schasinglulu 109*91f16700Schasinglulu INFO("region %d:\n", region); 110*91f16700Schasinglulu INFO("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n", 111*91f16700Schasinglulu sa, ea, apc[0], apc[1]); 112*91f16700Schasinglulu } 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu void emi_mpu_init(void) 116*91f16700Schasinglulu { 117*91f16700Schasinglulu struct emi_region_info_t region_info; 118*91f16700Schasinglulu 119*91f16700Schasinglulu /* SCP DRAM */ 120*91f16700Schasinglulu region_info.start = 0x50000000ULL; 121*91f16700Schasinglulu region_info.end = 0x51400000ULL; 122*91f16700Schasinglulu region_info.region = 2; 123*91f16700Schasinglulu SET_ACCESS_PERMISSION(region_info.apc, 1, 124*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 125*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 126*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 127*91f16700Schasinglulu NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION); 128*91f16700Schasinglulu emi_mpu_set_protection(®ion_info); 129*91f16700Schasinglulu 130*91f16700Schasinglulu /* DSP protect address */ 131*91f16700Schasinglulu region_info.start = 0x60000000ULL; /* dram base addr */ 132*91f16700Schasinglulu region_info.end = 0x610FFFFFULL; 133*91f16700Schasinglulu region_info.region = 3; 134*91f16700Schasinglulu SET_ACCESS_PERMISSION(region_info.apc, 1, 135*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 136*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 137*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION, 138*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION); 139*91f16700Schasinglulu emi_mpu_set_protection(®ion_info); 140*91f16700Schasinglulu 141*91f16700Schasinglulu /* Forbidden All */ 142*91f16700Schasinglulu region_info.start = 0x40000000ULL; /* dram base addr */ 143*91f16700Schasinglulu region_info.end = 0x1FFFF0000ULL; 144*91f16700Schasinglulu region_info.region = 5; 145*91f16700Schasinglulu SET_ACCESS_PERMISSION(region_info.apc, 1, 146*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 147*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 148*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 149*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION); 150*91f16700Schasinglulu emi_mpu_set_protection(®ion_info); 151*91f16700Schasinglulu 152*91f16700Schasinglulu dump_emi_mpu_regions(); 153*91f16700Schasinglulu } 154*91f16700Schasinglulu 155*91f16700Schasinglulu static inline uint64_t get_decoded_phys_addr(uint64_t addr) 156*91f16700Schasinglulu { 157*91f16700Schasinglulu return (addr << MPU_PHYSICAL_ADDR_SHIFT_BITS); 158*91f16700Schasinglulu } 159*91f16700Schasinglulu 160*91f16700Schasinglulu static inline uint32_t get_decoded_zone_id(uint32_t info) 161*91f16700Schasinglulu { 162*91f16700Schasinglulu return ((info & 0xFFFF0000) >> MPU_PHYSICAL_ADDR_SHIFT_BITS); 163*91f16700Schasinglulu } 164*91f16700Schasinglulu 165*91f16700Schasinglulu int32_t emi_mpu_sip_handler(uint64_t encoded_addr, uint64_t zone_size, uint64_t zone_info) 166*91f16700Schasinglulu { 167*91f16700Schasinglulu uint64_t phys_addr = get_decoded_phys_addr(encoded_addr); 168*91f16700Schasinglulu struct emi_region_info_t region_info; 169*91f16700Schasinglulu enum MPU_REQ_ORIGIN_ZONE_ID zone_id = get_decoded_zone_id(zone_info); 170*91f16700Schasinglulu 171*91f16700Schasinglulu INFO("encoded_addr = 0x%lx, zone_size = 0x%lx, zone_info = 0x%lx\n", 172*91f16700Schasinglulu encoded_addr, zone_size, zone_info); 173*91f16700Schasinglulu 174*91f16700Schasinglulu if (zone_id != MPU_REQ_ORIGIN_TEE_ZONE_SVP) { 175*91f16700Schasinglulu ERROR("Invalid param %s, %d\n", __func__, __LINE__); 176*91f16700Schasinglulu return MTK_SIP_E_INVALID_PARAM; 177*91f16700Schasinglulu } 178*91f16700Schasinglulu 179*91f16700Schasinglulu /* SVP DRAM */ 180*91f16700Schasinglulu region_info.start = phys_addr; 181*91f16700Schasinglulu region_info.end = phys_addr + zone_size; 182*91f16700Schasinglulu region_info.region = 4; 183*91f16700Schasinglulu SET_ACCESS_PERMISSION(region_info.apc, 1, 184*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 185*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 186*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, 187*91f16700Schasinglulu FORBIDDEN, FORBIDDEN, FORBIDDEN, SEC_RW); 188*91f16700Schasinglulu 189*91f16700Schasinglulu emi_mpu_set_protection(®ion_info); 190*91f16700Schasinglulu 191*91f16700Schasinglulu return 0; 192*91f16700Schasinglulu } 193