xref: /rk3399_ARM-atf/drivers/arm/gicv5/gicv5_main.c (revision dfb37a2df579ccf0e92c97515452b13ce2c9fba8)
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