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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
/*
* Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <common/debug.h>
#include <drivers/arm/css/css_mhu_doorbell.h>
#include <drivers/arm/css/scmi.h>
#include <drivers/arm/css/sds.h>
#include <drivers/arm/gic600_multichip.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <plat/arm/common/plat_arm.h>
#include "n1sdp_def.h"
/*
* Platform information structure stored in SDS.
* This structure holds information about platform's DDR
* size which will be used to zero out the memory before
* enabling the ECC capability as well as information
* about multichip setup
* - multichip mode
* - slave_count
* - Local DDR size in GB, DDR memory in master board
* - Remote DDR size in GB, DDR memory in slave board
*/
struct n1sdp_plat_info {
bool multichip_mode;
uint8_t slave_count;
uint8_t local_ddr_size;
uint8_t remote_ddr_size;
} __packed;
/*
* BL33 image information structure stored in SDS.
* This structure holds the source & destination addresses and
* the size of the BL33 image which will be loaded by BL31.
*/
struct n1sdp_bl33_info {
uint32_t bl33_src_addr;
uint32_t bl33_dst_addr;
uint32_t bl33_size;
};
static scmi_channel_plat_info_t n1sdp_scmi_plat_info = {
.scmi_mbx_mem = N1SDP_SCMI_PAYLOAD_BASE,
.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
.db_preserve_mask = 0xfffffffe,
.db_modify_mask = 0x1,
.ring_doorbell = &mhu_ring_doorbell
};
static struct gic600_multichip_data n1sdp_multichip_data __init = {
.rt_owner_base = PLAT_ARM_GICD_BASE,
.rt_owner = 0,
.chip_count = 1,
.chip_addrs = {
PLAT_ARM_GICD_BASE >> 16,
PLAT_ARM_GICD_BASE >> 16
},
.spi_ids = {
{32, 479},
{512, 959}
}
};
static uintptr_t n1sdp_multichip_gicr_frames[3] = {
PLAT_ARM_GICR_BASE,
PLAT_ARM_GICR_BASE + PLAT_ARM_REMOTE_CHIP_OFFSET,
0
};
scmi_channel_plat_info_t *plat_css_get_scmi_info(int channel_id)
{
return &n1sdp_scmi_plat_info;
}
const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
{
return css_scmi_override_pm_ops(ops);
}
/*
* N1SDP 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 DMC620. 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. BL33 binary cannot be copied to DDR memory
* before enabling ECC so copy_bl33 function is added to copy BL33 binary
* from IOFPGA-DDR3 memory to main DDR4 memory.
*/
void dmc_ecc_setup(uint8_t ddr_size_gb)
{
uint64_t dram2_size;
dram2_size = (ddr_size_gb * 1024UL * 1024UL * 1024UL) -
ARM_DRAM1_SIZE;
INFO("Zeroing DDR memories\n");
zero_normalmem((void *)ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
flush_dcache_range(ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
zero_normalmem((void *)ARM_DRAM2_BASE, dram2_size);
flush_dcache_range(ARM_DRAM2_BASE, dram2_size);
INFO("Enabling ECC on DMCs\n");
/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG);
mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG);
/* Enable ECC in DMCs */
mmio_setbits_32(N1SDP_DMC0_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN);
mmio_setbits_32(N1SDP_DMC1_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN);
/* Set DMCs to READY state */
mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
}
void remote_dmc_ecc_setup(uint8_t remote_ddr_size)
{
uint64_t remote_dram2_size;
remote_dram2_size = (remote_ddr_size * 1024UL * 1024UL * 1024UL) -
N1SDP_REMOTE_DRAM1_SIZE;
/* multichip setup */
INFO("Zeroing remote DDR memories\n");
zero_normalmem((void *)N1SDP_REMOTE_DRAM1_BASE,
N1SDP_REMOTE_DRAM1_SIZE);
flush_dcache_range(N1SDP_REMOTE_DRAM1_BASE, N1SDP_REMOTE_DRAM1_SIZE);
zero_normalmem((void *)N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
flush_dcache_range(N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
INFO("Enabling ECC on remote DMCs\n");
/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG,
N1SDP_DMC_MEMC_CMD_CONFIG);
mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG,
N1SDP_DMC_MEMC_CMD_CONFIG);
/* Enable ECC in DMCs */
mmio_setbits_32(N1SDP_REMOTE_DMC0_ERR0CTLR0_REG,
N1SDP_DMC_ERR0CTLR0_ECC_EN);
mmio_setbits_32(N1SDP_REMOTE_DMC1_ERR0CTLR0_REG,
N1SDP_DMC_ERR0CTLR0_ECC_EN);
/* Set DMCs to READY state */
mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
}
void copy_bl33(uint32_t src, uint32_t dst, uint32_t size)
{
uint32_t i;
INFO("Copying BL33 to DDR memory\n");
for (i = 0; i < size; i = i + 8)
mmio_write_64((dst + i), mmio_read_64(src + i));
for (i = 0; i < size; i = i + 8) {
if (mmio_read_64(src + i) != mmio_read_64(dst + i)) {
ERROR("Copy failed!\n");
panic();
}
}
}
void n1sdp_bl31_multichip_setup(void)
{
plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames);
gic600_multichip_init(&n1sdp_multichip_data);
}
void bl31_platform_setup(void)
{
int ret;
struct n1sdp_plat_info plat_info;
struct n1sdp_bl33_info bl33_info;
ret = sds_init();
if (ret != SDS_OK) {
ERROR("SDS initialization failed\n");
panic();
}
ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
N1SDP_SDS_PLATFORM_INFO_OFFSET,
&plat_info,
N1SDP_SDS_PLATFORM_INFO_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
if (ret != SDS_OK) {
ERROR("Error getting platform info from SDS\n");
panic();
}
/* Validate plat_info SDS */
if ((plat_info.local_ddr_size == 0)
|| (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
|| (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
|| (plat_info.slave_count > N1SDP_MAX_SLAVE_COUNT)) {
ERROR("platform info SDS is corrupted\n");
panic();
}
if (plat_info.multichip_mode) {
n1sdp_multichip_data.chip_count = plat_info.slave_count + 1;
n1sdp_bl31_multichip_setup();
}
arm_bl31_platform_setup();
dmc_ecc_setup(plat_info.local_ddr_size);
/* Check if remote memory is present */
if ((plat_info.multichip_mode) && (plat_info.remote_ddr_size != 0))
remote_dmc_ecc_setup(plat_info.remote_ddr_size);
ret = sds_struct_read(N1SDP_SDS_BL33_INFO_STRUCT_ID,
N1SDP_SDS_BL33_INFO_OFFSET,
&bl33_info,
N1SDP_SDS_BL33_INFO_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
if (ret != SDS_OK) {
ERROR("Error getting BL33 info from SDS\n");
panic();
}
copy_bl33(bl33_info.bl33_src_addr,
bl33_info.bl33_dst_addr,
bl33_info.bl33_size);
/*
* Pass platform information to BL33. This method is followed as
* currently there is no BL1/BL2 involved in boot flow of N1SDP.
* When TBBR is implemented for N1SDP, this method should be removed
* and platform information should be passed to BL33 using NT_FW_CONFIG
* passing mechanism.
*/
mmio_write_32(N1SDP_PLATFORM_INFO_BASE, *(uint32_t *)&plat_info);
}
|