1 /* 2 * Copyright (c) 2018-2024, 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, 511}, 56 {PLAT_ARM_GICD_BASE, 512, 991} 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 return css_scmi_override_pm_ops(ops); 75 } 76 77 /* 78 * N1SDP platform supports RDIMMs with ECC capability. To use the ECC 79 * capability, the entire DDR memory space has to be zeroed out before 80 * enabling the ECC bits in DMC620. Zeroing out several gigabytes of 81 * memory from SCP is quite time consuming so the following function 82 * is added to zero out the DDR memory from application processor which is 83 * much faster compared to SCP. Local DDR memory is zeroed out during BL2 84 * stage. If remote chip is connected, it's DDR memory is zeroed out here. 85 */ 86 87 void remote_dmc_ecc_setup(uint8_t remote_ddr_size) 88 { 89 uint64_t remote_dram2_size; 90 91 remote_dram2_size = (remote_ddr_size * 1024UL * 1024UL * 1024UL) - 92 N1SDP_REMOTE_DRAM1_SIZE; 93 /* multichip setup */ 94 INFO("Zeroing remote DDR memories\n"); 95 zero_normalmem((void *)N1SDP_REMOTE_DRAM1_BASE, 96 N1SDP_REMOTE_DRAM1_SIZE); 97 flush_dcache_range(N1SDP_REMOTE_DRAM1_BASE, N1SDP_REMOTE_DRAM1_SIZE); 98 zero_normalmem((void *)N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size); 99 flush_dcache_range(N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size); 100 101 INFO("Enabling ECC on remote DMCs\n"); 102 /* Set DMCs to CONFIG state before writing ERR0CTLR0 register */ 103 mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, 104 N1SDP_DMC_MEMC_CMD_CONFIG); 105 mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, 106 N1SDP_DMC_MEMC_CMD_CONFIG); 107 108 /* Enable ECC in DMCs */ 109 mmio_setbits_32(N1SDP_REMOTE_DMC0_ERR0CTLR0_REG, 110 N1SDP_DMC_ERR0CTLR0_ECC_EN); 111 mmio_setbits_32(N1SDP_REMOTE_DMC1_ERR0CTLR0_REG, 112 N1SDP_DMC_ERR0CTLR0_ECC_EN); 113 114 /* Set DMCs to READY state */ 115 mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY); 116 mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY); 117 } 118 119 void n1sdp_bl31_multichip_setup(void) 120 { 121 plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames); 122 gic600_multichip_init(&n1sdp_multichip_data); 123 } 124 125 void bl31_platform_setup(void) 126 { 127 int ret; 128 struct n1sdp_plat_info plat_info; 129 130 ret = sds_init(SDS_SCP_AP_REGION_ID); 131 if (ret != SDS_OK) { 132 ERROR("SDS initialization failed\n"); 133 panic(); 134 } 135 136 ret = sds_struct_read(SDS_SCP_AP_REGION_ID, 137 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