emi_mpu.c 3.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <common/debug.h>
#include <lib/mmio.h>
#include <emi_mpu.h>

int is_4GB(void)
{
	return 0; /* 8183 doesn't use 4GB */
}

/*
 * emi_mpu_set_region_protection: protect a region.
 * @start: start address of the region
 * @end: end address of the region
 * @region: EMI MPU region id
 * @access_permission: EMI MPU access permission
 * Return 0 for success, otherwise negative status code.
 */
int emi_mpu_set_region_protection(
	unsigned long start, unsigned long end,
	int region,
	unsigned int access_permission)
{
	int ret = 0;

	if (end <= start) {
		ERROR("[EMI][MTEE][MPU] Invalid address!.\n");
		return -1;
	}

	if (is_4GB()) {
		/* 4GB mode: emi_addr = phy_addr & 0xffff */
		start = EMI_PHY_OFFSET & 0xffff;
		end = EMI_PHY_OFFSET & 0xffff;
	} else {
		/* non-4GB mode: emi_addr = phy_addr - MEM_OFFSET */
		start = start - EMI_PHY_OFFSET;
		end = end - EMI_PHY_OFFSET;
	}

	/*Address 64KB alignment*/
	start = start >> 16;
	end = end >> 16;

	switch (region) {
	case 0:
		mmio_write_32(EMI_MPU_APC0, 0);
		mmio_write_32(EMI_MPU_SA0, start);
		mmio_write_32(EMI_MPU_EA0, end);
		mmio_write_32(EMI_MPU_APC0, access_permission);
		break;

	case 1:
		mmio_write_32(EMI_MPU_APC1, 0);
		mmio_write_32(EMI_MPU_SA1, start);
		mmio_write_32(EMI_MPU_EA1, end);
		mmio_write_32(EMI_MPU_APC1, access_permission);
		break;

	case 2:
		mmio_write_32(EMI_MPU_APC2, 0);
		mmio_write_32(EMI_MPU_SA2, start);
		mmio_write_32(EMI_MPU_EA2, end);
		mmio_write_32(EMI_MPU_APC2, access_permission);
		break;

	case 3:
		mmio_write_32(EMI_MPU_APC3, 0);
		mmio_write_32(EMI_MPU_SA3, start);
		mmio_write_32(EMI_MPU_EA3, end);
		mmio_write_32(EMI_MPU_APC3, access_permission);
		break;

	case 4:
		mmio_write_32(EMI_MPU_APC4, 0);
		mmio_write_32(EMI_MPU_SA4, start);
		mmio_write_32(EMI_MPU_EA4, end);
		mmio_write_32(EMI_MPU_APC4, access_permission);
		break;

	case 5:
		mmio_write_32(EMI_MPU_APC5, 0);
		mmio_write_32(EMI_MPU_SA5, start);
		mmio_write_32(EMI_MPU_EA5, end);
		mmio_write_32(EMI_MPU_APC5, access_permission);
		break;

	case 6:
		mmio_write_32(EMI_MPU_APC6, 0);
		mmio_write_32(EMI_MPU_SA6, start);
		mmio_write_32(EMI_MPU_EA6, end);
		mmio_write_32(EMI_MPU_APC6, access_permission);
		break;

	case 7:
		mmio_write_32(EMI_MPU_APC7, 0);
		mmio_write_32(EMI_MPU_SA7, start);
		mmio_write_32(EMI_MPU_EA7, end);
		mmio_write_32(EMI_MPU_APC7, access_permission);
		break;

	default:
		ret = -1;
		break;
	}

	return ret;
}

void dump_emi_mpu_regions(void)
{
	unsigned int apc, sa, ea;
	unsigned int apc_addr = EMI_MPU_APC0;
	unsigned int sa_addr = EMI_MPU_SA0;
	unsigned int ea_addr = EMI_MPU_EA0;
	int i;

	for (i = 0; i < 8; ++i) {
		apc = mmio_read_32(apc_addr + i * 4);
		sa = mmio_read_32(sa_addr + i * 4);
		ea = mmio_read_32(ea_addr + i * 4);
		WARN("region %d:\n", i);
		WARN("\tapc:0x%x, sa:0x%x, ea:0x%x\n", apc, sa, ea);
	}
}

void emi_mpu_init(void)
{
	/* Set permission */
	emi_mpu_set_region_protection(0x40000000UL, 0x4FFFFFFFUL, 0,
				(FORBIDDEN << 3 | FORBIDDEN << 6));
	emi_mpu_set_region_protection(0x50000000UL, 0x528FFFFFUL, 1,
				(FORBIDDEN << 6));
	emi_mpu_set_region_protection(0x52900000UL, 0x5FFFFFFFUL, 2,
				(FORBIDDEN << 3 | FORBIDDEN << 6));
141
	emi_mpu_set_region_protection(0x60000000UL, 0xFFFFFFFFUL, 3,
142
				(FORBIDDEN << 3 | FORBIDDEN << 6));
143
	emi_mpu_set_region_protection(0x100000000UL, 0x23FFFFFFFUL, 4,
144
145
146
147
				(FORBIDDEN << 3 | FORBIDDEN << 6));
	dump_emi_mpu_regions();
}