summaryrefslogtreecommitdiffstats
path: root/plat/arm/board/morello/morello_bl2_setup.c
blob: da1f7ae10068197dd7aa1c3c551ae164df4e5a6a (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <common/debug.h>
#include <drivers/arm/css/sds.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <plat/arm/common/plat_arm.h>

#include "morello_def.h"
#include <platform_def.h>

#ifdef TARGET_PLATFORM_FVP
/*
 * Platform information structure stored in SDS.
 * This structure holds information about platform's DDR
 * size
 *	- Local DDR size in bytes, DDR memory in main board
 */
struct morello_plat_info {
	uint64_t local_ddr_size;
} __packed;
#else
/*
 * Platform information structure stored in SDS.
 * This structure holds information about platform's DDR
 * size which is an information about multichip setup
 *	- Local DDR size in bytes, DDR memory in main board
 *	- Remote DDR size in bytes, DDR memory in remote board
 *	- remote_chip_count
 *	- multichip mode
 *	- scc configuration
 */
struct morello_plat_info {
	uint64_t local_ddr_size;
	uint64_t remote_ddr_size;
	uint8_t remote_chip_count;
	bool multichip_mode;
	uint32_t scc_config;
} __packed;
#endif

/* Compile time assertion to ensure the size of structure is 18 bytes */
CASSERT(sizeof(struct morello_plat_info) == MORELLO_SDS_PLATFORM_INFO_SIZE,
		assert_invalid_plat_info_size);

#ifdef TARGET_PLATFORM_SOC
/*
 * Morello platform supports RDIMMs with ECC capability. To use the ECC
 * capability, the entire DDR memory space has to be zeroed out before
 * enabling the ECC bits in DMC-Bing. Zeroing out several gigabytes of
 * memory from SCP is quite time consuming so the following function
 * is added to zero out the DDR memory from application processor which is
 * much faster compared to SCP.
 */

static void dmc_ecc_setup(struct morello_plat_info *plat_info)
{
	uint64_t dram2_size;
	uint32_t val;
	uint64_t tag_mem_base;
	uint64_t usable_mem_size;

	INFO("Total DIMM size: %uGB\n",
			(uint32_t)(plat_info->local_ddr_size / 0x40000000));

	assert(plat_info->local_ddr_size > ARM_DRAM1_SIZE);
	dram2_size = plat_info->local_ddr_size - ARM_DRAM1_SIZE;

	INFO("Zeroing DDR memory range 0x80000000 - 0xFFFFFFFF\n");
	zero_normalmem((void *)ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
	flush_dcache_range(ARM_DRAM1_BASE, ARM_DRAM1_SIZE);

	INFO("Zeroing DDR memory range 0x%llx - 0x%llx\n",
		ARM_DRAM2_BASE, ARM_DRAM2_BASE + dram2_size);
	zero_normalmem((void *)ARM_DRAM2_BASE, dram2_size);
	flush_dcache_range(ARM_DRAM2_BASE, dram2_size);

	/* Clear previous ECC errors while zeroing out the memory */
	val = mmio_read_32(MORELLO_DMC0_ERR2STATUS_REG);
	mmio_write_32(MORELLO_DMC0_ERR2STATUS_REG, val);

	val = mmio_read_32(MORELLO_DMC1_ERR2STATUS_REG);
	mmio_write_32(MORELLO_DMC1_ERR2STATUS_REG, val);

	/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
	mmio_write_32(MORELLO_DMC0_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_CONFIG);
	mmio_write_32(MORELLO_DMC1_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_CONFIG);

	while ((mmio_read_32(MORELLO_DMC0_MEMC_STATUS_REG) &
			MORELLO_DMC_MEMC_STATUS_MASK) !=
			MORELLO_DMC_MEMC_CMD_CONFIG) {
		continue;
	}

	while ((mmio_read_32(MORELLO_DMC1_MEMC_STATUS_REG) &
			MORELLO_DMC_MEMC_STATUS_MASK) !=
			MORELLO_DMC_MEMC_CMD_CONFIG) {
		continue;
	}

	/* Configure Bing client/server mode based on SCC configuration */
	if (plat_info->scc_config & MORELLO_SCC_CLIENT_MODE_MASK) {
		INFO("Configuring DMC Bing in client mode\n");
		usable_mem_size = plat_info->local_ddr_size -
			(plat_info->local_ddr_size / 128ULL);

		/* Linear DDR address */
		tag_mem_base = usable_mem_size;
		tag_mem_base = tag_mem_base / 4;

		/* Reverse translation */
		if (tag_mem_base < ARM_DRAM1_BASE) {
			tag_mem_base += ARM_DRAM1_BASE;
		} else {
			tag_mem_base = tag_mem_base - ARM_DRAM1_BASE +
				ARM_DRAM2_BASE;
		}

		mmio_write_32(MORELLO_DMC0_CAP_CTRL_REG, 0x1);
		mmio_write_32(MORELLO_DMC1_CAP_CTRL_REG, 0x1);
		mmio_write_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x1);
		mmio_write_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x1);

		if (plat_info->scc_config & MORELLO_SCC_C1_TAG_CACHE_EN_MASK) {
			mmio_setbits_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x2);
			mmio_setbits_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x2);
			INFO("C1 Tag Cache Enabled\n");
		}

		if (plat_info->scc_config & MORELLO_SCC_C2_TAG_CACHE_EN_MASK) {
			mmio_setbits_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x4);
			mmio_setbits_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x4);
			INFO("C2 Tag Cache Enabled\n");
		}

		mmio_write_32(MORELLO_DMC0_MEM_ADDR_CTL,
				(uint32_t)tag_mem_base);
		mmio_write_32(MORELLO_DMC1_MEM_ADDR_CTL,
				(uint32_t)tag_mem_base);
		mmio_write_32(MORELLO_DMC0_MEM_ADDR_CTL2,
				(uint32_t)(tag_mem_base >> 32));
		mmio_write_32(MORELLO_DMC1_MEM_ADDR_CTL2,
				(uint32_t)(tag_mem_base >> 32));

		mmio_setbits_32(MORELLO_DMC0_MEM_ACCESS_CTL,
				MORELLO_DMC_MEM_ACCESS_DIS);
		mmio_setbits_32(MORELLO_DMC1_MEM_ACCESS_CTL,
				MORELLO_DMC_MEM_ACCESS_DIS);

		INFO("Tag base set to 0x%lx\n", tag_mem_base);
		plat_info->local_ddr_size = usable_mem_size;
	} else {
		INFO("Configuring DMC Bing in server mode\n");
		mmio_write_32(MORELLO_DMC0_CAP_CTRL_REG, 0x0);
		mmio_write_32(MORELLO_DMC1_CAP_CTRL_REG, 0x0);
	}

	INFO("Enabling ECC on DMCs\n");
	/* Enable ECC in DMCs */
	mmio_setbits_32(MORELLO_DMC0_ERR0CTLR0_REG,
		MORELLO_DMC_ERR0CTLR0_ECC_EN);
	mmio_setbits_32(MORELLO_DMC1_ERR0CTLR0_REG,
		MORELLO_DMC_ERR0CTLR0_ECC_EN);

	/* Set DMCs to READY state */
	mmio_write_32(MORELLO_DMC0_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_READY);
	mmio_write_32(MORELLO_DMC1_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_READY);

	while ((mmio_read_32(MORELLO_DMC0_MEMC_STATUS_REG) &
			MORELLO_DMC_MEMC_STATUS_MASK) !=
			MORELLO_DMC_MEMC_CMD_READY) {
		continue;
	}

	while ((mmio_read_32(MORELLO_DMC1_MEMC_STATUS_REG) &
			MORELLO_DMC_MEMC_STATUS_MASK) !=
			MORELLO_DMC_MEMC_CMD_READY) {
		continue;
	}
}
#endif

void bl2_platform_setup(void)
{
	int ret;
	struct morello_plat_info plat_info;

	ret = sds_init();
	if (ret != SDS_OK) {
		ERROR("SDS initialization failed. ret:%d\n", ret);
		panic();
	}

	ret = sds_struct_read(MORELLO_SDS_PLATFORM_INFO_STRUCT_ID,
				MORELLO_SDS_PLATFORM_INFO_OFFSET,
				&plat_info,
				MORELLO_SDS_PLATFORM_INFO_SIZE,
				SDS_ACCESS_MODE_NON_CACHED);
	if (ret != SDS_OK) {
		ERROR("Error getting platform info from SDS. ret:%d\n", ret);
		panic();
	}

	/* Validate plat_info SDS */
#ifdef TARGET_PLATFORM_FVP
	if (plat_info.local_ddr_size == 0U) {
#else
	if ((plat_info.local_ddr_size == 0U)
		|| (plat_info.local_ddr_size > MORELLO_MAX_DDR_CAPACITY)
		|| (plat_info.remote_ddr_size > MORELLO_MAX_DDR_CAPACITY)
		|| (plat_info.remote_chip_count > MORELLO_MAX_REMOTE_CHIP_COUNT)
		) {
#endif
		ERROR("platform info SDS is corrupted\n");
		panic();
	}

#ifdef TARGET_PLATFORM_SOC
	dmc_ecc_setup(&plat_info);
#endif
	arm_bl2_platform_setup();
}