123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /*
- * 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++)
- 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;
- }
|