18cef63d6SBoyan Karatotev /* 28cef63d6SBoyan Karatotev * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. 38cef63d6SBoyan Karatotev * 48cef63d6SBoyan Karatotev * SPDX-License-Identifier: BSD-3-Clause 58cef63d6SBoyan Karatotev */ 613b62814SBoyan Karatotev 7*dfb37a2dSBoyan Karatotev #include <assert.h> 813b62814SBoyan Karatotev #include <cdefs.h> 913b62814SBoyan Karatotev 1082b228baSBoyan Karatotev #include <arch.h> 1113b62814SBoyan Karatotev #include <arch_features.h> 1282b228baSBoyan Karatotev #include <arch_helpers.h> 1382b228baSBoyan Karatotev 1413b62814SBoyan Karatotev #include <bl31/interrupt_mgmt.h> 1513b62814SBoyan Karatotev #include <common/debug.h> 1613b62814SBoyan Karatotev #include <drivers/arm/gicv5.h> 1713b62814SBoyan Karatotev 18*dfb37a2dSBoyan Karatotev static void irs_configure_wire(uintptr_t base_addr, uint32_t wire, uint8_t domain) 19*dfb37a2dSBoyan Karatotev { 20*dfb37a2dSBoyan Karatotev write_irs_spi_selr(base_addr, wire); 21*dfb37a2dSBoyan Karatotev WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 22*dfb37a2dSBoyan Karatotev 23*dfb37a2dSBoyan Karatotev write_irs_spi_domainr(base_addr, domain); 24*dfb37a2dSBoyan Karatotev WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 25*dfb37a2dSBoyan Karatotev } 26*dfb37a2dSBoyan Karatotev 27*dfb37a2dSBoyan Karatotev static void irs_enable(const struct gicv5_irs *config) 28*dfb37a2dSBoyan Karatotev { 29*dfb37a2dSBoyan Karatotev uint32_t spi_base, spi_range; 30*dfb37a2dSBoyan Karatotev uintptr_t base_addr = config->el3_config_frame; 31*dfb37a2dSBoyan Karatotev 32*dfb37a2dSBoyan Karatotev spi_base = EXTRACT(IRS_IDR7_SPI_BASE, read_irs_idr7(base_addr)); 33*dfb37a2dSBoyan Karatotev spi_range = EXTRACT(IRS_IDR6_SPI_IRS_RANGE, read_irs_idr6(base_addr)); 34*dfb37a2dSBoyan Karatotev 35*dfb37a2dSBoyan Karatotev if (spi_range == 0U) { 36*dfb37a2dSBoyan Karatotev assert(config->num_spis == 0U); 37*dfb37a2dSBoyan Karatotev } 38*dfb37a2dSBoyan Karatotev 39*dfb37a2dSBoyan Karatotev /* default all wires to the NS domain */ 40*dfb37a2dSBoyan Karatotev for (uint32_t i = spi_base; i < spi_base + spi_range; i++) { 41*dfb37a2dSBoyan Karatotev irs_configure_wire(base_addr, i, INTDMN_NS); 42*dfb37a2dSBoyan Karatotev } 43*dfb37a2dSBoyan Karatotev 44*dfb37a2dSBoyan Karatotev for (uint32_t i = 0U; i < config->num_spis; i++) { 45*dfb37a2dSBoyan Karatotev assert((config->spis[i].id >= spi_base) && 46*dfb37a2dSBoyan Karatotev (config->spis[i].id < spi_base + spi_range)); 47*dfb37a2dSBoyan Karatotev 48*dfb37a2dSBoyan Karatotev irs_configure_wire(base_addr, config->spis[i].id, config->spis[i].domain); 49*dfb37a2dSBoyan Karatotev 50*dfb37a2dSBoyan Karatotev /* don't (can't) configure TM of wires for other domains */ 51*dfb37a2dSBoyan Karatotev if (config->spis[i].domain == INTDMN_EL3) { 52*dfb37a2dSBoyan Karatotev write_irs_spi_cfgr(base_addr, config->spis[i].tm); 53*dfb37a2dSBoyan Karatotev WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base_addr); 54*dfb37a2dSBoyan Karatotev } 55*dfb37a2dSBoyan Karatotev } 56*dfb37a2dSBoyan Karatotev } 57*dfb37a2dSBoyan Karatotev 5813b62814SBoyan Karatotev void __init gicv5_driver_init(void) 5913b62814SBoyan Karatotev { 60*dfb37a2dSBoyan Karatotev for (size_t i = 0U; i < plat_gicv5_driver_data.num_irss; i++) { 61*dfb37a2dSBoyan Karatotev irs_enable(&plat_gicv5_driver_data.irss[i]); 62*dfb37a2dSBoyan Karatotev } 6313b62814SBoyan Karatotev } 6413b62814SBoyan Karatotev 6513b62814SBoyan Karatotev /* 6613b62814SBoyan Karatotev * There exists a theoretical configuration where FEAT_RME is enabled 6713b62814SBoyan Karatotev * without using TrustZone (i.e., no Secure world present). Currently, 6813b62814SBoyan Karatotev * there is no reliable mechanism to detect this scenario at runtime. 6913b62814SBoyan Karatotev * 7013b62814SBoyan Karatotev * TODO: Add support for this configuration in the future if required. 7113b62814SBoyan Karatotev */ 7213b62814SBoyan Karatotev bool gicv5_has_interrupt_type(unsigned int type) 7313b62814SBoyan Karatotev { 7413b62814SBoyan Karatotev switch (type) { 7513b62814SBoyan Karatotev case INTR_TYPE_EL3: 7613b62814SBoyan Karatotev case INTR_TYPE_S_EL1: 7713b62814SBoyan Karatotev case INTR_TYPE_NS: 7813b62814SBoyan Karatotev return true; 7913b62814SBoyan Karatotev case INTR_TYPE_RL: 8013b62814SBoyan Karatotev return is_feat_rme_supported(); 8113b62814SBoyan Karatotev default: 8213b62814SBoyan Karatotev return false; 8313b62814SBoyan Karatotev } 8413b62814SBoyan Karatotev } 8513b62814SBoyan Karatotev 8613b62814SBoyan Karatotev uint8_t gicv5_get_pending_interrupt_type(void) 8713b62814SBoyan Karatotev { 8813b62814SBoyan Karatotev /* there is no pending interrupt expected */ 8913b62814SBoyan Karatotev return INTR_TYPE_INVAL; 9013b62814SBoyan Karatotev } 9182b228baSBoyan Karatotev 9282b228baSBoyan Karatotev /* TODO: these will probably end up contexted. Make Linux work for now */ 9382b228baSBoyan Karatotev void gicv5_enable_ppis(void) 9482b228baSBoyan Karatotev { 9582b228baSBoyan Karatotev uint64_t domainr = 0U; 9682b228baSBoyan Karatotev 9782b228baSBoyan Karatotev /* the only ones described in the device tree at the moment */ 9882b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_PMUIRQ, INTDMN_NS); 9982b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_GICMNT, INTDMN_NS); 10082b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_CNTHP, INTDMN_NS); 10182b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_CNTV, INTDMN_NS); 10282b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_CNTPS, INTDMN_NS); 10382b228baSBoyan Karatotev write_icc_ppi_domainr(domainr, PPI_CNTP, INTDMN_NS); 10482b228baSBoyan Karatotev 10582b228baSBoyan Karatotev write_icc_ppi_domainr0_el3(domainr); 10682b228baSBoyan Karatotev } 107