mirror of
				https://github.com/riscv-software-src/opensbi
				synced 2025-11-03 21:48:45 +00:00 
			
		
		
		
	Each APLIC CLRIE register allows disabling 32 interrupt sources at
a time by writing -1 so no need to write CLRIE register separately
for each interrupt source.
Fixes: 99792653de29 ("lib: utils/irqchip: Add APLIC initialization library")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
		
	
			
		
			
				
	
	
		
			283 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			283 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SPDX-License-Identifier: BSD-2-Clause
 | 
						|
 *
 | 
						|
 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
 | 
						|
 * Copyright (c) 2022 Ventana Micro Systems Inc.
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *   Anup Patel <anup.patel@wdc.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include <sbi/riscv_io.h>
 | 
						|
#include <sbi/sbi_console.h>
 | 
						|
#include <sbi/sbi_domain.h>
 | 
						|
#include <sbi/sbi_error.h>
 | 
						|
#include <sbi_utils/irqchip/aplic.h>
 | 
						|
 | 
						|
#define APLIC_MAX_IDC			(1UL << 14)
 | 
						|
#define APLIC_MAX_SOURCE		1024
 | 
						|
 | 
						|
#define APLIC_DOMAINCFG		0x0000
 | 
						|
#define APLIC_DOMAINCFG_IE		(1 << 8)
 | 
						|
#define APLIC_DOMAINCFG_DM		(1 << 2)
 | 
						|
#define APLIC_DOMAINCFG_BE		(1 << 0)
 | 
						|
 | 
						|
#define APLIC_SOURCECFG_BASE		0x0004
 | 
						|
#define APLIC_SOURCECFG_D		(1 << 10)
 | 
						|
#define APLIC_SOURCECFG_CHILDIDX_MASK	0x000003ff
 | 
						|
#define APLIC_SOURCECFG_SM_MASK	0x00000007
 | 
						|
#define APLIC_SOURCECFG_SM_INACTIVE	0x0
 | 
						|
#define APLIC_SOURCECFG_SM_DETACH	0x1
 | 
						|
#define APLIC_SOURCECFG_SM_EDGE_RISE	0x4
 | 
						|
#define APLIC_SOURCECFG_SM_EDGE_FALL	0x5
 | 
						|
#define APLIC_SOURCECFG_SM_LEVEL_HIGH	0x6
 | 
						|
#define APLIC_SOURCECFG_SM_LEVEL_LOW	0x7
 | 
						|
 | 
						|
#define APLIC_MMSICFGADDR		0x1bc0
 | 
						|
#define APLIC_MMSICFGADDRH		0x1bc4
 | 
						|
#define APLIC_SMSICFGADDR		0x1bc8
 | 
						|
#define APLIC_SMSICFGADDRH		0x1bcc
 | 
						|
 | 
						|
#define APLIC_xMSICFGADDRH_L		(1UL << 31)
 | 
						|
#define APLIC_xMSICFGADDRH_HHXS_MASK	0x1f
 | 
						|
#define APLIC_xMSICFGADDRH_HHXS_SHIFT	24
 | 
						|
#define APLIC_xMSICFGADDRH_LHXS_MASK	0x7
 | 
						|
#define APLIC_xMSICFGADDRH_LHXS_SHIFT	20
 | 
						|
#define APLIC_xMSICFGADDRH_HHXW_MASK	0x7
 | 
						|
#define APLIC_xMSICFGADDRH_HHXW_SHIFT	16
 | 
						|
#define APLIC_xMSICFGADDRH_LHXW_MASK	0xf
 | 
						|
#define APLIC_xMSICFGADDRH_LHXW_SHIFT	12
 | 
						|
#define APLIC_xMSICFGADDRH_BAPPN_MASK	0xfff
 | 
						|
 | 
						|
#define APLIC_xMSICFGADDR_PPN_SHIFT	12
 | 
						|
 | 
						|
#define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
 | 
						|
	((1UL << (__lhxs)) - 1)
 | 
						|
 | 
						|
#define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
 | 
						|
	((1UL << (__lhxw)) - 1)
 | 
						|
#define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
 | 
						|
	((__lhxs))
 | 
						|
#define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
 | 
						|
	(APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
 | 
						|
	 APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
 | 
						|
 | 
						|
#define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
 | 
						|
	((1UL << (__hhxw)) - 1)
 | 
						|
#define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
 | 
						|
	((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
 | 
						|
#define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
 | 
						|
	(APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
 | 
						|
	 APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
 | 
						|
 | 
						|
#define APLIC_SETIP_BASE		0x1c00
 | 
						|
#define APLIC_SETIPNUM			0x1cdc
 | 
						|
 | 
						|
#define APLIC_CLRIP_BASE		0x1d00
 | 
						|
#define APLIC_CLRIPNUM			0x1ddc
 | 
						|
 | 
						|
#define APLIC_SETIE_BASE		0x1e00
 | 
						|
#define APLIC_SETIENUM			0x1edc
 | 
						|
 | 
						|
#define APLIC_CLRIE_BASE		0x1f00
 | 
						|
#define APLIC_CLRIENUM			0x1fdc
 | 
						|
 | 
						|
#define APLIC_SETIPNUM_LE		0x2000
 | 
						|
#define APLIC_SETIPNUM_BE		0x2004
 | 
						|
 | 
						|
#define APLIC_TARGET_BASE		0x3004
 | 
						|
#define APLIC_TARGET_HART_IDX_SHIFT	18
 | 
						|
#define APLIC_TARGET_HART_IDX_MASK	0x3fff
 | 
						|
#define APLIC_TARGET_GUEST_IDX_SHIFT	12
 | 
						|
#define APLIC_TARGET_GUEST_IDX_MASK	0x3f
 | 
						|
#define APLIC_TARGET_IPRIO_MASK	0xff
 | 
						|
#define APLIC_TARGET_EIID_MASK	0x7ff
 | 
						|
 | 
						|
#define APLIC_IDC_BASE			0x4000
 | 
						|
#define APLIC_IDC_SIZE			32
 | 
						|
 | 
						|
#define APLIC_IDC_IDELIVERY		0x00
 | 
						|
 | 
						|
#define APLIC_IDC_IFORCE		0x04
 | 
						|
 | 
						|
#define APLIC_IDC_ITHRESHOLD		0x08
 | 
						|
 | 
						|
#define APLIC_IDC_TOPI			0x18
 | 
						|
#define APLIC_IDC_TOPI_ID_SHIFT	16
 | 
						|
#define APLIC_IDC_TOPI_ID_MASK	0x3ff
 | 
						|
#define APLIC_IDC_TOPI_PRIO_MASK	0xff
 | 
						|
 | 
						|
#define APLIC_IDC_CLAIMI		0x1c
 | 
						|
 | 
						|
#define APLIC_DEFAULT_PRIORITY		1
 | 
						|
#define APLIC_DISABLE_IDELIVERY		0
 | 
						|
#define APLIC_ENABLE_IDELIVERY		1
 | 
						|
#define APLIC_DISABLE_ITHRESHOLD	1
 | 
						|
#define APLIC_ENABLE_ITHRESHOLD		0
 | 
						|
 | 
						|
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
 | 
						|
				void *msicfgaddr, void *msicfgaddrH)
 | 
						|
{
 | 
						|
	u32 val;
 | 
						|
	unsigned long base_ppn;
 | 
						|
 | 
						|
	/* Check if MSI config is already locked */
 | 
						|
	if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* Compute the MSI base PPN */
 | 
						|
	base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
 | 
						|
	base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
 | 
						|
	base_ppn &= ~APLIC_xMSICFGADDR_PPN_LHX(msicfg->lhxw, msicfg->lhxs);
 | 
						|
	base_ppn &= ~APLIC_xMSICFGADDR_PPN_HHX(msicfg->hhxw, msicfg->hhxs);
 | 
						|
 | 
						|
	/* Write the lower MSI config register */
 | 
						|
	writel((u32)base_ppn, msicfgaddr);
 | 
						|
 | 
						|
	/* Write the upper MSI config register */
 | 
						|
	val = (((u64)base_ppn) >> 32) &
 | 
						|
		APLIC_xMSICFGADDRH_BAPPN_MASK;
 | 
						|
	val |= (msicfg->lhxw & APLIC_xMSICFGADDRH_LHXW_MASK)
 | 
						|
		<< APLIC_xMSICFGADDRH_LHXW_SHIFT;
 | 
						|
	val |= (msicfg->hhxw & APLIC_xMSICFGADDRH_HHXW_MASK)
 | 
						|
		<< APLIC_xMSICFGADDRH_HHXW_SHIFT;
 | 
						|
	val |= (msicfg->lhxs & APLIC_xMSICFGADDRH_LHXS_MASK)
 | 
						|
		<< APLIC_xMSICFGADDRH_LHXS_SHIFT;
 | 
						|
	val |= (msicfg->hhxs & APLIC_xMSICFGADDRH_HHXS_MASK)
 | 
						|
		<< APLIC_xMSICFGADDRH_HHXS_SHIFT;
 | 
						|
	writel(val, msicfgaddrH);
 | 
						|
}
 | 
						|
 | 
						|
static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
 | 
						|
{
 | 
						|
	if (APLIC_xMSICFGADDRH_LHXS_MASK < msicfg->lhxs)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	if (APLIC_xMSICFGADDRH_LHXW_MASK < msicfg->lhxw)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	if (APLIC_xMSICFGADDRH_HHXS_MASK < msicfg->hhxs)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	if (APLIC_xMSICFGADDRH_HHXW_MASK < msicfg->hhxw)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int aplic_cold_irqchip_init(struct aplic_data *aplic)
 | 
						|
{
 | 
						|
	int rc;
 | 
						|
	u32 i, j, tmp;
 | 
						|
	struct sbi_domain_memregion reg;
 | 
						|
	struct aplic_delegate_data *deleg;
 | 
						|
	u32 first_deleg_irq, last_deleg_irq;
 | 
						|
 | 
						|
	/* Sanity checks */
 | 
						|
	if (!aplic ||
 | 
						|
	    !aplic->num_source || APLIC_MAX_SOURCE <= aplic->num_source ||
 | 
						|
	    APLIC_MAX_IDC <= aplic->num_idc)
 | 
						|
		return SBI_EINVAL;
 | 
						|
	if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
 | 
						|
		rc = aplic_check_msicfg(&aplic->msicfg_mmode);
 | 
						|
		if (rc)
 | 
						|
			return rc;
 | 
						|
	}
 | 
						|
	if (aplic->targets_mmode && aplic->has_msicfg_smode) {
 | 
						|
		rc = aplic_check_msicfg(&aplic->msicfg_smode);
 | 
						|
		if (rc)
 | 
						|
			return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Set domain configuration to 0 */
 | 
						|
	writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
 | 
						|
 | 
						|
	/* Disable all interrupts */
 | 
						|
	for (i = 0; i <= aplic->num_source; i += 32)
 | 
						|
		writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
 | 
						|
				     (i / 32) * sizeof(u32)));
 | 
						|
 | 
						|
	/* Set interrupt type and priority for all interrupts */
 | 
						|
	for (i = 1; i <= aplic->num_source; i++) {
 | 
						|
		/* Set IRQ source configuration to 0 */
 | 
						|
		writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
 | 
						|
			  (i - 1) * sizeof(u32)));
 | 
						|
		/* Set IRQ target hart index and priority to 1 */
 | 
						|
		writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
 | 
						|
						APLIC_TARGET_BASE +
 | 
						|
						(i - 1) * sizeof(u32)));
 | 
						|
	}
 | 
						|
 | 
						|
	/* Configure IRQ delegation */
 | 
						|
	first_deleg_irq = -1U;
 | 
						|
	last_deleg_irq = 0;
 | 
						|
	for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
 | 
						|
		deleg = &aplic->delegate[i];
 | 
						|
		if (!deleg->first_irq || !deleg->last_irq)
 | 
						|
			continue;
 | 
						|
		if (aplic->num_source < deleg->first_irq ||
 | 
						|
		    aplic->num_source < deleg->last_irq)
 | 
						|
			continue;
 | 
						|
		if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
 | 
						|
			continue;
 | 
						|
		if (deleg->first_irq > deleg->last_irq) {
 | 
						|
			tmp = deleg->first_irq;
 | 
						|
			deleg->first_irq = deleg->last_irq;
 | 
						|
			deleg->last_irq = tmp;
 | 
						|
		}
 | 
						|
		if (deleg->first_irq < first_deleg_irq)
 | 
						|
			first_deleg_irq = deleg->first_irq;
 | 
						|
		if (last_deleg_irq < deleg->last_irq)
 | 
						|
			last_deleg_irq = deleg->last_irq;
 | 
						|
		for (j = deleg->first_irq; j <= deleg->last_irq; j++)
 | 
						|
			writel(APLIC_SOURCECFG_D | deleg->child_index,
 | 
						|
				(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
 | 
						|
				(j - 1) * sizeof(u32)));
 | 
						|
	}
 | 
						|
 | 
						|
	/* Default initialization of IDC structures */
 | 
						|
	for (i = 0; i < aplic->num_idc; i++) {
 | 
						|
		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
 | 
						|
			  i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
 | 
						|
		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
 | 
						|
			  i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
 | 
						|
		writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
 | 
						|
						  APLIC_IDC_BASE +
 | 
						|
						  (i * APLIC_IDC_SIZE) +
 | 
						|
						  APLIC_IDC_ITHRESHOLD));
 | 
						|
	}
 | 
						|
 | 
						|
	/* MSI configuration */
 | 
						|
	if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
 | 
						|
		aplic_writel_msicfg(&aplic->msicfg_mmode,
 | 
						|
				(void *)(aplic->addr + APLIC_MMSICFGADDR),
 | 
						|
				(void *)(aplic->addr + APLIC_MMSICFGADDRH));
 | 
						|
	}
 | 
						|
	if (aplic->targets_mmode && aplic->has_msicfg_smode) {
 | 
						|
		aplic_writel_msicfg(&aplic->msicfg_smode,
 | 
						|
				(void *)(aplic->addr + APLIC_SMSICFGADDR),
 | 
						|
				(void *)(aplic->addr + APLIC_SMSICFGADDRH));
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Add APLIC region to the root domain if:
 | 
						|
	 * 1) It targets M-mode of any HART directly or via MSIs
 | 
						|
	 * 2) All interrupts are delegated to some child APLIC
 | 
						|
	 */
 | 
						|
	if (aplic->targets_mmode ||
 | 
						|
	    ((first_deleg_irq < last_deleg_irq) &&
 | 
						|
	    (last_deleg_irq == aplic->num_source) &&
 | 
						|
	    (first_deleg_irq == 1))) {
 | 
						|
		sbi_domain_memregion_init(aplic->addr, aplic->size,
 | 
						|
					  (SBI_DOMAIN_MEMREGION_MMIO |
 | 
						|
					   SBI_DOMAIN_MEMREGION_M_READABLE |
 | 
						|
					   SBI_DOMAIN_MEMREGION_M_WRITABLE),
 | 
						|
					  ®);
 | 
						|
		rc = sbi_domain_root_add_memregion(®);
 | 
						|
		if (rc)
 | 
						|
			return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |