18454f0d6SDawei Chien /*
2c842cc0eSBo-Chen Chen * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
38454f0d6SDawei Chien *
48454f0d6SDawei Chien * SPDX-License-Identifier: BSD-3-Clause
58454f0d6SDawei Chien */
68454f0d6SDawei Chien
78454f0d6SDawei Chien #include <string.h>
88454f0d6SDawei Chien #include <common/debug.h>
98454f0d6SDawei Chien #include <lib/mmio.h>
1034d9d619SDawei Chien #include <smccc_helpers.h>
1134d9d619SDawei Chien
128454f0d6SDawei Chien #include <emi_mpu.h>
138454f0d6SDawei Chien #include <lib/mtk_init/mtk_init.h>
14c842cc0eSBo-Chen Chen #include <mtk_sip_svc.h>
158454f0d6SDawei Chien
168454f0d6SDawei Chien #if ENABLE_EMI_MPU_SW_LOCK
178454f0d6SDawei Chien static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
188454f0d6SDawei Chien #endif
198454f0d6SDawei Chien
208454f0d6SDawei Chien #define EMI_MPU_START_MASK (0x00FFFFFF)
218454f0d6SDawei Chien #define EMI_MPU_END_MASK (0x00FFFFFF)
228454f0d6SDawei Chien #define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
238454f0d6SDawei Chien #define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
248454f0d6SDawei Chien
_emi_mpu_set_protection(unsigned int start,unsigned int end,unsigned int apc)258454f0d6SDawei Chien static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
268454f0d6SDawei Chien unsigned int apc)
278454f0d6SDawei Chien {
288454f0d6SDawei Chien unsigned int dgroup;
298454f0d6SDawei Chien unsigned int region;
308454f0d6SDawei Chien
318454f0d6SDawei Chien region = (start >> 24) & 0xFF;
328454f0d6SDawei Chien start &= EMI_MPU_START_MASK;
338454f0d6SDawei Chien dgroup = (end >> 24) & 0xFF;
348454f0d6SDawei Chien end &= EMI_MPU_END_MASK;
358454f0d6SDawei Chien
368454f0d6SDawei Chien if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
378454f0d6SDawei Chien WARN("invalid region, domain\n");
388454f0d6SDawei Chien return -1;
398454f0d6SDawei Chien }
408454f0d6SDawei Chien
418454f0d6SDawei Chien #if ENABLE_EMI_MPU_SW_LOCK
42*fc77c69aSHaohao Sun if (region_lock_state[region] == LOCK) {
438454f0d6SDawei Chien WARN("invalid region\n");
448454f0d6SDawei Chien return -1;
458454f0d6SDawei Chien }
468454f0d6SDawei Chien
478454f0d6SDawei Chien if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
48*fc77c69aSHaohao Sun region_lock_state[region] = LOCK;
498454f0d6SDawei Chien }
508454f0d6SDawei Chien
518454f0d6SDawei Chien apc &= EMI_MPU_APC_SW_LOCK_MASK;
528454f0d6SDawei Chien #else
538454f0d6SDawei Chien apc &= EMI_MPU_APC_HW_LOCK_MASK;
548454f0d6SDawei Chien #endif
558454f0d6SDawei Chien
568454f0d6SDawei Chien if ((start >= DRAM_OFFSET) && (end >= start)) {
578454f0d6SDawei Chien start -= DRAM_OFFSET;
588454f0d6SDawei Chien end -= DRAM_OFFSET;
598454f0d6SDawei Chien } else {
608454f0d6SDawei Chien WARN("invalid range\n");
618454f0d6SDawei Chien return -1;
628454f0d6SDawei Chien }
638454f0d6SDawei Chien
648454f0d6SDawei Chien mmio_write_32(EMI_MPU_SA(region), start);
658454f0d6SDawei Chien mmio_write_32(EMI_MPU_EA(region), end);
668454f0d6SDawei Chien mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
678454f0d6SDawei Chien
688454f0d6SDawei Chien #if defined(SUB_EMI_MPU_BASE)
698454f0d6SDawei Chien mmio_write_32(SUB_EMI_MPU_SA(region), start);
708454f0d6SDawei Chien mmio_write_32(SUB_EMI_MPU_EA(region), end);
718454f0d6SDawei Chien mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
728454f0d6SDawei Chien #endif
738454f0d6SDawei Chien return 0;
748454f0d6SDawei Chien }
758454f0d6SDawei Chien
emi_mpu_clear_protection(unsigned int region)76*fc77c69aSHaohao Sun int emi_mpu_clear_protection(unsigned int region)
77*fc77c69aSHaohao Sun {
78*fc77c69aSHaohao Sun unsigned int dgroup;
79*fc77c69aSHaohao Sun
80*fc77c69aSHaohao Sun if (region >= EMI_MPU_REGION_NUM) {
81*fc77c69aSHaohao Sun WARN("invalid region number\n");
82*fc77c69aSHaohao Sun return -1;
83*fc77c69aSHaohao Sun }
84*fc77c69aSHaohao Sun
85*fc77c69aSHaohao Sun #if ENABLE_EMI_MPU_SW_LOCK
86*fc77c69aSHaohao Sun if (region_lock_state[region] == LOCK) {
87*fc77c69aSHaohao Sun WARN("SW:region is locked\n");
88*fc77c69aSHaohao Sun return -1;
89*fc77c69aSHaohao Sun }
90*fc77c69aSHaohao Sun #endif
91*fc77c69aSHaohao Sun if (mmio_read_32(EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
92*fc77c69aSHaohao Sun WARN("HW:EMI-MPU region is locked\n");
93*fc77c69aSHaohao Sun return -1;
94*fc77c69aSHaohao Sun }
95*fc77c69aSHaohao Sun
96*fc77c69aSHaohao Sun #if defined(SUB_EMI_MPU_BASE)
97*fc77c69aSHaohao Sun if (mmio_read_32(SUB_EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
98*fc77c69aSHaohao Sun WARN("HW:SUB EMI-MPU region is locked\n");
99*fc77c69aSHaohao Sun return -1;
100*fc77c69aSHaohao Sun }
101*fc77c69aSHaohao Sun #endif
102*fc77c69aSHaohao Sun
103*fc77c69aSHaohao Sun for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
104*fc77c69aSHaohao Sun mmio_write_32(EMI_MPU_APC(region, dgroup), 0x0);
105*fc77c69aSHaohao Sun
106*fc77c69aSHaohao Sun mmio_write_32(EMI_MPU_SA(region), 0x0);
107*fc77c69aSHaohao Sun mmio_write_32(EMI_MPU_EA(region), 0x0);
108*fc77c69aSHaohao Sun
109*fc77c69aSHaohao Sun #if defined(SUB_EMI_MPU_BASE)
110*fc77c69aSHaohao Sun for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
111*fc77c69aSHaohao Sun mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), 0x0);
112*fc77c69aSHaohao Sun
113*fc77c69aSHaohao Sun mmio_write_32(SUB_EMI_MPU_SA(region), 0);
114*fc77c69aSHaohao Sun mmio_write_32(SUB_EMI_MPU_EA(region), 0);
115*fc77c69aSHaohao Sun #endif
116*fc77c69aSHaohao Sun return 0;
117*fc77c69aSHaohao Sun }
118*fc77c69aSHaohao Sun
119*fc77c69aSHaohao Sun
dump_emi_mpu_regions(void)1208454f0d6SDawei Chien static void dump_emi_mpu_regions(void)
1218454f0d6SDawei Chien {
1228454f0d6SDawei Chien int region, i;
1238454f0d6SDawei Chien
1248454f0d6SDawei Chien /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
1258454f0d6SDawei Chien for (region = 0; region < 8; ++region) {
1268454f0d6SDawei Chien INFO("region %d:\n", region);
1278454f0d6SDawei Chien INFO("\tsa: 0x%x, ea: 0x%x\n",
1288454f0d6SDawei Chien mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
1298454f0d6SDawei Chien
1308454f0d6SDawei Chien for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
1318454f0d6SDawei Chien INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
1328454f0d6SDawei Chien }
1338454f0d6SDawei Chien }
1348454f0d6SDawei Chien }
1358454f0d6SDawei Chien
emi_mpu_set_protection(struct emi_region_info_t * region_info)1368454f0d6SDawei Chien int emi_mpu_set_protection(struct emi_region_info_t *region_info)
1378454f0d6SDawei Chien {
1388454f0d6SDawei Chien unsigned int start, end;
1398454f0d6SDawei Chien int i;
1408454f0d6SDawei Chien
1418454f0d6SDawei Chien if (region_info->region >= EMI_MPU_REGION_NUM) {
1428454f0d6SDawei Chien WARN("invalid region\n");
1438454f0d6SDawei Chien return -1;
1448454f0d6SDawei Chien }
1458454f0d6SDawei Chien
1468454f0d6SDawei Chien start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
1478454f0d6SDawei Chien (region_info->region << 24);
1488454f0d6SDawei Chien
1498454f0d6SDawei Chien for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
1508454f0d6SDawei Chien end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
1518454f0d6SDawei Chien
1528454f0d6SDawei Chien if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
1538454f0d6SDawei Chien WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
1548454f0d6SDawei Chien start, end, region_info->apc[i]);
1558454f0d6SDawei Chien }
1568454f0d6SDawei Chien }
1578454f0d6SDawei Chien
1588454f0d6SDawei Chien return 0;
1598454f0d6SDawei Chien }
1608454f0d6SDawei Chien
mtk_emi_mpu_sip_handler(u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * handle,struct smccc_res * smccc_ret)161c842cc0eSBo-Chen Chen u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2,
162c842cc0eSBo-Chen Chen u_register_t x3, u_register_t x4,
163c842cc0eSBo-Chen Chen void *handle, struct smccc_res *smccc_ret)
164c842cc0eSBo-Chen Chen {
165d07eee24SDawei Chien return (u_register_t) emi_mpu_optee_handler(x1, x2, x3);
166c842cc0eSBo-Chen Chen }
167c842cc0eSBo-Chen Chen DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler);
168c842cc0eSBo-Chen Chen
emi_mpu_init(void)1698454f0d6SDawei Chien int emi_mpu_init(void)
1708454f0d6SDawei Chien {
1718454f0d6SDawei Chien INFO("[%s] emi mpu initialization\n", __func__);
1728454f0d6SDawei Chien
1738454f0d6SDawei Chien set_emi_mpu_regions();
1748454f0d6SDawei Chien dump_emi_mpu_regions();
1758454f0d6SDawei Chien
1768454f0d6SDawei Chien return 0;
1778454f0d6SDawei Chien }
1788454f0d6SDawei Chien MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
179