1 /* 2 * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <cdefs.h> 9 10 #include <arch.h> 11 #include <arch_features.h> 12 #include <arch_helpers.h> 13 14 #include <bl31/interrupt_mgmt.h> 15 #include <common/debug.h> 16 #include <drivers/arm/gicv5.h> 17 18 static void irs_configure_wire(uintptr_t base_addr, uint32_t wire, uint8_t domain) 19 { 20 write_irs_spi_selr(base_addr, wire); 21 WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 22 23 write_irs_spi_domainr(base_addr, domain); 24 WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 25 } 26 27 static void irs_enable(const struct gicv5_irs *config) 28 { 29 uint32_t spi_base, spi_range; 30 uintptr_t base_addr = config->el3_config_frame; 31 32 spi_base = EXTRACT(IRS_IDR7_SPI_BASE, read_irs_idr7(base_addr)); 33 spi_range = EXTRACT(IRS_IDR6_SPI_IRS_RANGE, read_irs_idr6(base_addr)); 34 35 if (spi_range == 0U) { 36 assert(config->num_spis == 0U); 37 } 38 39 /* default all wires to the NS domain */ 40 for (uint32_t i = spi_base; i < spi_base + spi_range; i++) { 41 irs_configure_wire(base_addr, i, INTDMN_NS); 42 } 43 44 for (uint32_t i = 0U; i < config->num_spis; i++) { 45 assert((config->spis[i].id >= spi_base) && 46 (config->spis[i].id < spi_base + spi_range)); 47 48 irs_configure_wire(base_addr, config->spis[i].id, config->spis[i].domain); 49 50 /* don't (can't) configure TM of wires for other domains */ 51 if (config->spis[i].domain == INTDMN_EL3) { 52 write_irs_spi_cfgr(base_addr, config->spis[i].tm); 53 WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 54 } 55 } 56 } 57 58 void __init gicv5_driver_init(void) 59 { 60 for (size_t i = 0U; i < plat_gicv5_driver_data.num_irss; i++) { 61 irs_enable(&plat_gicv5_driver_data.irss[i]); 62 } 63 } 64 65 /* 66 * There exists a theoretical configuration where FEAT_RME is enabled 67 * without using TrustZone (i.e., no Secure world present). Currently, 68 * there is no reliable mechanism to detect this scenario at runtime. 69 * 70 * TODO: Add support for this configuration in the future if required. 71 */ 72 bool gicv5_has_interrupt_type(unsigned int type) 73 { 74 switch (type) { 75 case INTR_TYPE_EL3: 76 case INTR_TYPE_S_EL1: 77 case INTR_TYPE_NS: 78 return true; 79 case INTR_TYPE_RL: 80 return is_feat_rme_supported(); 81 default: 82 return false; 83 } 84 } 85 86 uint8_t gicv5_get_pending_interrupt_type(void) 87 { 88 /* there is no pending interrupt expected */ 89 return INTR_TYPE_INVAL; 90 } 91 92 /* TODO: these will probably end up contexted. Make Linux work for now */ 93 void gicv5_enable_ppis(void) 94 { 95 uint64_t domainr = 0U; 96 97 /* the only ones described in the device tree at the moment */ 98 write_icc_ppi_domainr(domainr, PPI_PMUIRQ, INTDMN_NS); 99 write_icc_ppi_domainr(domainr, PPI_GICMNT, INTDMN_NS); 100 write_icc_ppi_domainr(domainr, PPI_CNTHP, INTDMN_NS); 101 write_icc_ppi_domainr(domainr, PPI_CNTV, INTDMN_NS); 102 write_icc_ppi_domainr(domainr, PPI_CNTPS, INTDMN_NS); 103 write_icc_ppi_domainr(domainr, PPI_CNTP, INTDMN_NS); 104 105 write_icc_ppi_domainr0_el3(domainr); 106 } 107