xref: /rk3399_ARM-atf/plat/arm/board/n1sdp/n1sdp_bl31_setup.c (revision ff8f1c5fe1667dab360ac4cab1309a4cac65c2cd)
1 /*
2  * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <common/debug.h>
8 #include <drivers/arm/css/css_mhu_doorbell.h>
9 #include <drivers/arm/css/scmi.h>
10 #include <drivers/arm/css/sds.h>
11 #include <drivers/arm/gic600_multichip.h>
12 #include <lib/mmio.h>
13 #include <lib/utils.h>
14 #include <plat/arm/common/plat_arm.h>
15 
16 #include "n1sdp_def.h"
17 #include "n1sdp_private.h"
18 #include <platform_def.h>
19 
20 /*
21  * Platform information structure stored in SDS.
22  * This structure holds information about platform's DDR
23  * size which will be used to zero out the memory before
24  * enabling the ECC capability as well as information
25  * about multichip setup
26  * 	- multichip mode
27  * 	- secondary_count
28  * 	- Local DDR size in GB, DDR memory in master board
29  * 	- Remote DDR size in GB, DDR memory in secondary board
30  */
31 struct n1sdp_plat_info {
32 	bool multichip_mode;
33 	uint8_t secondary_count;
34 	uint8_t local_ddr_size;
35 	uint8_t remote_ddr_size;
36 } __packed;
37 
38 static scmi_channel_plat_info_t n1sdp_scmi_plat_info = {
39 	.scmi_mbx_mem = N1SDP_SCMI_PAYLOAD_BASE,
40 	.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
41 	.db_preserve_mask = 0xfffffffe,
42 	.db_modify_mask = 0x1,
43 	.ring_doorbell = &mhu_ring_doorbell
44 };
45 
46 static struct gic600_multichip_data n1sdp_multichip_data __init = {
47 	.rt_owner_base = PLAT_ARM_GICD_BASE,
48 	.rt_owner = 0,
49 	.chip_count = 1,
50 	.chip_addrs = {
51 		PLAT_ARM_GICD_BASE >> 16,
52 		PLAT_ARM_GICD_BASE >> 16
53 	},
54 	.spi_ids = {
55 		{PLAT_ARM_GICD_BASE, 32, 479},
56 		{PLAT_ARM_GICD_BASE, 512, 959}
57 	}
58 };
59 
60 static uintptr_t n1sdp_multichip_gicr_frames[3] = {
61 	PLAT_ARM_GICR_BASE,
62 	PLAT_ARM_GICR_BASE + PLAT_ARM_REMOTE_CHIP_OFFSET,
63 	0
64 };
65 
66 scmi_channel_plat_info_t *plat_css_get_scmi_info(unsigned int channel_id)
67 {
68 	return &n1sdp_scmi_plat_info;
69 }
70 
71 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
72 {
73 	ops->pwr_domain_off = n1sdp_pwr_domain_off;
74 	ops->pwr_domain_suspend = n1sdp_pwr_domain_suspend;
75 	return css_scmi_override_pm_ops(ops);
76 }
77 
78 /*
79  * N1SDP platform supports RDIMMs with ECC capability. To use the ECC
80  * capability, the entire DDR memory space has to be zeroed out before
81  * enabling the ECC bits in DMC620. Zeroing out several gigabytes of
82  * memory from SCP is quite time consuming so the following function
83  * is added to zero out the DDR memory from application processor which is
84  * much faster compared to SCP. Local DDR memory is zeroed out during BL2
85  * stage. If remote chip is connected, it's DDR memory is zeroed out here.
86  */
87 
88 void remote_dmc_ecc_setup(uint8_t remote_ddr_size)
89 {
90 	uint64_t remote_dram2_size;
91 
92 	remote_dram2_size = (remote_ddr_size * 1024UL * 1024UL * 1024UL) -
93 				N1SDP_REMOTE_DRAM1_SIZE;
94 	/* multichip setup */
95 	INFO("Zeroing remote DDR memories\n");
96 	zero_normalmem((void *)N1SDP_REMOTE_DRAM1_BASE,
97 			N1SDP_REMOTE_DRAM1_SIZE);
98 	flush_dcache_range(N1SDP_REMOTE_DRAM1_BASE, N1SDP_REMOTE_DRAM1_SIZE);
99 	zero_normalmem((void *)N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
100 	flush_dcache_range(N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
101 
102 	INFO("Enabling ECC on remote DMCs\n");
103 	/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
104 	mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG,
105 			N1SDP_DMC_MEMC_CMD_CONFIG);
106 	mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG,
107 			N1SDP_DMC_MEMC_CMD_CONFIG);
108 
109 	/* Enable ECC in DMCs */
110 	mmio_setbits_32(N1SDP_REMOTE_DMC0_ERR0CTLR0_REG,
111 			N1SDP_DMC_ERR0CTLR0_ECC_EN);
112 	mmio_setbits_32(N1SDP_REMOTE_DMC1_ERR0CTLR0_REG,
113 			N1SDP_DMC_ERR0CTLR0_ECC_EN);
114 
115 	/* Set DMCs to READY state */
116 	mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
117 	mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
118 }
119 
120 void n1sdp_bl31_multichip_setup(void)
121 {
122 	plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames);
123 	gic600_multichip_init(&n1sdp_multichip_data);
124 }
125 
126 void bl31_platform_setup(void)
127 {
128 	int ret;
129 	struct n1sdp_plat_info plat_info;
130 
131 	ret = sds_init();
132 	if (ret != SDS_OK) {
133 		ERROR("SDS initialization failed\n");
134 		panic();
135 	}
136 
137 	ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
138 				N1SDP_SDS_PLATFORM_INFO_OFFSET,
139 				&plat_info,
140 				N1SDP_SDS_PLATFORM_INFO_SIZE,
141 				SDS_ACCESS_MODE_NON_CACHED);
142 	if (ret != SDS_OK) {
143 		ERROR("Error getting platform info from SDS\n");
144 		panic();
145 	}
146 	/* Validate plat_info SDS */
147 	if ((plat_info.local_ddr_size == 0)
148 		|| (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
149 		|| (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
150 		|| (plat_info.secondary_count > N1SDP_MAX_SECONDARY_COUNT)) {
151 		ERROR("platform info SDS is corrupted\n");
152 		panic();
153 	}
154 
155 	if (plat_info.multichip_mode) {
156 		n1sdp_multichip_data.chip_count = plat_info.secondary_count + 1;
157 		n1sdp_bl31_multichip_setup();
158 	}
159 	arm_bl31_platform_setup();
160 
161 	/* Check if remote memory is present */
162 	if ((plat_info.multichip_mode) && (plat_info.remote_ddr_size != 0))
163 		remote_dmc_ecc_setup(plat_info.remote_ddr_size);
164 }
165 
166 #if defined(SPD_spmd) && (SPMC_AT_EL3 == 0)
167 /*
168  * A dummy implementation of the platform handler for Group0 secure interrupt.
169  */
170 int plat_spmd_handle_group0_interrupt(uint32_t intid)
171 {
172 	(void)intid;
173 	return -1;
174 }
175 #endif /*defined(SPD_spmd) && (SPMC_AT_EL3 == 0)*/
176