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