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